6

我的测试框架目前基于一个 test-runner 实用程序,它本身是从 Eclipse pydev python test-runner 派生的。我正在改用 Nose,它具有我的自定义测试运行器的许多功能,但似乎是质量更好的代码。

我的测试套件包括许多以前从未运行过的抽象测试类。标准的 python 测试运行程序(和我的自定义运行程序)仅运行 unittest.TestCase 和 unittest.TestSuite 的实例。

我注意到,自从我切换到 Nose 后,它几乎可以运行任何以名称“test”开头的东西,这很烦人……因为我们用于 test-mixins 的命名约定也看起来像 Nose 的测试类。以前这些从未作为测试运行,因为它们不是 TestCase 或 TestSuite 的实例。

显然,我可以重新命名这些方法以从它们的名称中排除“测试”一词……这需要一段时间,因为测试框架非常大并且有很多继承。另一方面,如果有一种方法可以让 Nose 只将 TestCases 和 TestSuites 视为可运行的......而不是其他任何东西,那就太好了。

这可以做到吗?

4

5 回答 5

6

您可以尝试-m使用nosetests. 从文档:

测试类是在测试模块中定义的与 testMatch 匹配的类,或者是 unittest.TestCase 的子类

-m设置它testMatch,这样您就可以禁用以 test 开头的任何测试

另一件事是您可以添加__test__ = False到您的测试用例类声明中,以将其标记为“不是测试”。

于 2010-06-25T13:57:25.523 回答
2

如果你想要一个真正抽象的测试类,你可以从对象继承抽象类,然后在测试用例中继承。

例如:

class AbstractTestcases(object):
    def test_my_function_does_something(self):
        self.assertEquals("bar", self.func())

然后将其用于:

class TestMyFooFunc(AbstractTestcases, unittest.TestCase):
    def setUp(self):
        self.func = lambda: "foo"

然后nosetests将仅拾取 in 中的测试用例TestMyFooFunc,而不拾取AbstractTestCases.

于 2015-04-23T01:06:41.653 回答
1

您可以使用鼻子的 --attr 参数来指定 unittest.TestCase 所具有的属性。例如,我使用:

nosetests --attr="assertAlmostEqual"

通过使用andor匹配,您可以更加小心:

nosetests -A "assertAlmostEqual or addTest"

有关方法/属性的完整列表,请参阅unittest 的文档,以及 Nose对 --attr 插件功能的描述

于 2012-11-30T02:36:19.440 回答
0

您还可以在测试用例级别使用多重继承,并让基类object仅继承。看到这个线程

class MyBase(object):
   def finishsetup(self):
       self.z=self.x+self.y

   def test1(self):
       self.assertEqual(self.z, self.x+self.y)

   def test2(self):
       self.assert_(self.x > self.y)

class RealCase1(MyBase, unittest.TestCase):
   def setUp(self):
       self.x=10
       self.y=5
       MyBase.finishsetup(self)

class RealCase2(MyBase, unittest.TestCase):
   def setUp(self):
       self.x=42
       self.y=13
       MyBase.finishsetup(self) 
于 2016-12-08T16:40:14.497 回答
0

@nailxx 答案的一个附录:

您可以__test__ = False在父类中设置,然后在子类化时使用元类(请参阅此问题以及一些精彩的解释)将其设置回 True 。

(最后,我找到了使用元类的借口!)

虽然__test__是双下划线属性,但我们必须明确将其设置为,因为不设置它会导致 python 只是在MROTrue中进一步查找该属性并将其评估为。False

因此,我们需要在类实例化时检查父类之一是否具有__test__ = False. 如果是这种情况并且当前类定义尚未设置__test__,我们将添加'__test__': True到属性 dict。

生成的代码如下所示:

class TestWhenSubclassedMeta(type):
    """Metaclass that sets `__test__` back to `True` when subclassed.

    Usage:

        >>> class GenericTestCase(TestCase, metaclass=TestWhenSubclassed):
        ...     __test__ = False
        ...
        ...     def test_something(self):
        ...         self.fail("This test is executed in a subclass, only.")
        ...
        ...
        >>> class SpecificTestCase(GenericTestCase):
        ...     pass

    """

    def __new__(mcs, name, bases, attrs):
        ATTR_NAME = '__test__'
        VALUE_TO_RESET = False
        RESET_VALUE = True

        values = [getattr(base, ATTR_NAME) for base in bases
                  if hasattr(base, ATTR_NAME)]

        # only reset if the first attribute is `VALUE_TO_RESET`
        try:
            first_value = values[0]
        except IndexError:
            pass
        else:
            if first_value == VALUE_TO_RESET and ATTR_NAME not in attrs:
                attrs[ATTR_NAME] = RESET_VALUE

        return super().__new__(mcs, name, bases, attrs)

可以将其扩展到一些更隐含的行为,例如“如果名称以 . 开头Abstract,则__test__ = False自动设置”,但为了清楚起见,我自己会保留显式分配。


让我粘贴简单的单元测试来演示行为 - 并提醒每个人在引入功能后应该花两分钟测试他们的代码。

from unittest import TestCase

from .base import TestWhenSubclassedMeta


class SubclassesTestCase(TestCase):
    def test_subclass_resetted(self):
        class Base(metaclass=TestWhenSubclassedMeta):
            __test__ = False

        class C(Base):
            pass

        self.assertTrue(C.__test__)
        self.assertIn('__test__', C.__dict__)

    def test_subclass_not_resetted(self):
        class Base(metaclass=TestWhenSubclassedMeta):
            __test__ = True

        class C(Base):
            pass

        self.assertTrue(C.__test__)
        self.assertNotIn('__test__', C.__dict__)

    def test_subclass_attr_not_set(self):
        class Base(metaclass=TestWhenSubclassedMeta):
            pass

        class C(Base):
            pass

        with self.assertRaises(AttributeError):
            getattr(C, '__test__')
于 2016-09-04T15:25:17.050 回答