我有一些测试数据,想为每个项目创建一个单元测试。我的第一个想法是这样做的:

import unittest

l = [["foo", "a", "a",], ["bar", "a", "b"], ["lee", "b", "b"]]

class TestSequence(unittest.TestCase):
    def testsample(self):
        for name, a,b in l:
            print "test", name
            self.assertEqual(a,b)

if __name__ == '__main__':
    unittest.main()

这样做的缺点是它在一个测试中处理所有数据。我想在飞行中为每个项目生成一个测试。有什么建议吗?


当前回答

元编程很有趣,但它也会碍事。这里的大多数解决方案都很难:

有选择地启动测试 指向给出测试名称的代码

所以,我的第一个建议是遵循简单/显式路径(适用于任何测试运行程序):

import unittest

class TestSequence(unittest.TestCase):

    def _test_complex_property(self, a, b):
        self.assertEqual(a,b)

    def test_foo(self):
        self._test_complex_property("a", "a")
    def test_bar(self):
        self._test_complex_property("a", "b")
    def test_lee(self):
        self._test_complex_property("b", "b")

if __name__ == '__main__':
    unittest.main()

既然我们不应该重复,我的第二个建议建立在Javier的回答之上:接受基于属性的测试。假设库:

“在生成测试用例方面比我们人类更加无情地迂回” 会提供简单的计数例子吗 与任何测试运行程序一起工作 具有更多有趣的特性(统计数据、额外的测试输出……) 类TestSequence (unittest.TestCase): st.text @given (st.text () () Def test_complex_property(self, a, b): self.assertEqual (a, b)

为了测试您的特定示例,只需添加:

    @example("a", "a")
    @example("a", "b")
    @example("b", "b")

为了只运行一个特定的示例,您可以注释掉其他示例(提供的示例将首先运行)。你可能想要使用@given(st.nothing())。另一种选择是将整个区块替换为:

    @given(st.just("a"), st.just("b"))

好的,您没有不同的测试名称。但也许你只需要:

被测属性的描述性名称。 哪个输入会导致失败(伪造的例子)。

有趣的例子

其他回答

您将从尝试testscenario库中受益。

testscenes为python unittest风格的测试提供了干净的依赖注入。这可以用于接口测试(通过单个测试套件测试许多实现)或经典的依赖项注入(在测试代码本身的外部提供依赖项测试,允许在不同情况下轻松测试)。

这可以通过使用pytest来完成。只需要编写test_me.py文件的内容:

import pytest

@pytest.mark.parametrize('name, left, right', [['foo', 'a', 'a'],
                                               ['bar', 'a', 'b'],
                                               ['baz', 'b', 'b']])
def test_me(name, left, right):
    assert left == right, name

并使用py命令运行测试。Test——tb=短test_me.py。然后输出如下所示:

=========================== test session starts ============================
platform darwin -- Python 2.7.6 -- py-1.4.23 -- pytest-2.6.1
collected 3 items

test_me.py .F.

================================= FAILURES =================================
_____________________________ test_me[bar-a-b] _____________________________
test_me.py:8: in test_me
    assert left == right, name
E   AssertionError: bar
==================== 1 failed, 2 passed in 0.01 seconds ====================

这很简单!此外,pytest还有更多的功能,如fixture、标记、断言等。

除了使用setattr,我们还可以在Python 3.2及更高版本中使用load_tests。

class Test(unittest.TestCase):
    pass

def _test(self, file_name):
    open(file_name, 'r') as f:
        self.assertEqual('test result',f.read())

def _generate_test(file_name):
    def test(self):
        _test(self, file_name)
    return test

def _generate_tests():
    for file in files:
        file_name = os.path.splitext(os.path.basename(file))[0]
        setattr(Test, 'test_%s' % file_name, _generate_test(file))

test_cases = (Test,)

def load_tests(loader, tests, pattern):
    _generate_tests()
    suite = TestSuite()
    for test_class in test_cases:
        tests = loader.loadTestsFromTestCase(test_class)
        suite.addTests(tests)
    return suite

if __name__ == '__main__':
    _generate_tests()
    unittest.main()

只使用元类,如这里所示;

class DocTestMeta(type):
    """
    Test functions are generated in metaclass due to the way some
    test loaders work. For example, setupClass() won't get called
    unless there are other existing test methods, and will also
    prevent unit test loader logic being called before the test
    methods have been defined.
    """
    def __init__(self, name, bases, attrs):
        super(DocTestMeta, self).__init__(name, bases, attrs)

    def __new__(cls, name, bases, attrs):
        def func(self):
            """Inner test method goes here"""
            self.assertTrue(1)

        func.__name__ = 'test_sample'
        attrs[func.__name__] = func
        return super(DocTestMeta, cls).__new__(cls, name, bases, attrs)

class ExampleTestCase(TestCase):
    """Our example test case, with no methods defined"""
    __metaclass__ = DocTestMeta

输出:

test_sample (ExampleTestCase) ... OK

基于元类的答案在Python 3中仍然有效,但必须使用元类参数,而不是__metaclass__属性,例如:

class ExampleTestCase(TestCase,metaclass=DocTestMeta):
    pass