13

我正在使用 python unittest 模块进行一些测试;但是,它非常重复。

我有很多数据想一遍又一遍地通过相同的测试,检查是否正确。但是,我必须为每个人定义一个测试。

例如,我想做类似的事情。我知道我可以使用生成器来做到这一点(在以前的线程中找到它)。但是是否有替代方案,甚至可能使用不同的测试模块?

任何建议都会很棒。


import unittest

class TestData(unittest.TestCase):
    def testNumbers(self):
        numbers = [0,11,222,33,44,555,6,77,8,9999]
        for i in numbers:
            self.assertEqual(i, 33)
4

7 回答 7

11

Bill Gribble 建议的解决方案示例代码如下所示:

import unittest

class DataTestCase(unittest.TestCase):
    def __init__(self, number):
        unittest.TestCase.__init__(self, methodName='testOneNumber')
        self.number = number

    def testOneNumber(self):
        self.assertEqual(self.number, 33)

    def shortDescription(self):
        # We need to distinguish between instances of this test case.
        return 'DataTestCase for number %d' % self.number


def get_test_data_suite():
    numbers = [0,11,222,33,44,555,6,77,8,9999]
    return unittest.TestSuite([DataTestCase(n) for n in numbers])

if __name__ == '__main__':
    testRunner = unittest.TextTestRunner()
    testRunner.run(get_test_data_suite())
于 2010-10-13T11:48:35.240 回答
6

从 Python 3.4 开始,您可以使用unittest.TestCase.subTest(msg=None, **params)上下文管理器(文档)。这将允许您通过仅添加一个语句来实现您想要的。

这是您修改为使用的示例subTest()

import unittest

class TestData(unittest.TestCase):
    def testNumbers(self):
        numbers = [0, 11, 222, 33, 44, 555, 6, 77, 8, 9999]
        for i in numbers:
            with self.subTest(i=i):  # added statement
                self.assertEqual(i, 33)
于 2019-01-22T13:31:53.397 回答
5

您可能需要考虑使用 unittest.TestSuite 类,它允许您动态构建一组 unittest.TestCase 实例,这些实例将单独运行。您的 unittest.TestCase 子类应该只定义一个测试方法,该类接受一个构造参数,传入值以针对该特定实例进行测试。

于 2010-10-12T14:25:53.260 回答
4

ddt旨在解决您所要求的unittest[*]。

例如:

import ddt
import unittest

@ddt.ddt
class EvalTests(unittest.TestCase):

    @ddt.data(
            ('1', 1),
            ('1 == 1',  True),
            ('1 == 2',  False),
            ('1 + 2',   4),  ## This will fail
    )
    def test_eval_expressions(self, case):
        expr, exp_value = case
        self.assertEqual(eval(expr), exp_value)

当你运行它时,你会得到 4 个 TestCases 而不是一个:

$ python -m unittest  -v  test_eval.py
test_eval_expressions_1___1___1_ (test_eval.EvalTests) ... ok
test_eval_expressions_2___1__1___True_ (test_eval.EvalTests) ... ok
test_eval_expressions_3___1__2___False_ (test_eval.EvalTests) ... ok
test_eval_expressions_4___1_2___4_ (test_eval.EvalTests) ... FAIL

======================================================================
FAIL: test_eval_expressions_4___1_2___4_ (test_eval.EvalTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/python/lib/site-packages/ddt.py", line 129, in wrapper
    return func(self, *args, **kwargs)
  File "/Work/test_eval.py", line 15, in test_eval_expressions
    self.assertEqual(eval(expr), exp_value)
AssertionError: 3 != 4

----------------------------------------------------------------------
Ran 4 tests in 0.002s

FAILED (failures=1)

请注意,ddt尝试为生成的 TC 提供名称。

使用 pip 安装它:

pip install ddt

[*] pythonicpytest框架 ( pytest.mark.parametrize) 的相同解决方案已集成到核心工具中,pytest仅针对此功能值得切换。

于 2016-08-09T18:14:15.853 回答
2

在另一篇文章中,我偶然发现了 鼻子测试 它更适合数据驱动测试。


class Test_data():
    def testNumbers():
        numbers = [0,11,222,33,44,555,6,77,8,9999]
        for i in numbers:
            yield checkNumber, num

def checkNumber(num):
    assert num == 33

上面的代码与我的第一篇文章完全相同。不需要导入,只需编写一个 python 类。

您可以通过键入以下内容执行测试:

nosetests filename

于 2010-10-15T13:44:07.990 回答
2

在循环中运行断言的问题在于,如果其中一个断言失败,您不知道是哪个值导致它(在您的示例中,它会在 上失败0,但在调试之前您不知道)。另一方面,重复self.assertEqual(i, 33)是一个更糟糕的想法,因为它引入了代码重复。

我在测试中所做的是在测试中创建一个简单的、名称短小的内部函数,并使用不同的参数调用它。所以你的函数看起来像这样:

import unittest

class TestData(unittest.TestCase):
    def testNumbers(self):
        def eq(i):
            self.assertEqual(i, 33)
        eq(0)
        eq(11)
        eq(222)
        eq(33)
        eq(44)
        eq(555)
        ... 

这样,当断言失败时0,您会立即在unittest模块打印的堆栈跟踪中看到它。

于 2010-10-12T13:59:36.987 回答
0

这个答案的衍生,这对我来说不太管用。在我不处理大量数据的情况下,我确实需要使用不同的输入运行相同的测试。以下测试正在使用create_acreate_b我要自定义的方法。

要求是使用相同的自定义运行两个测试。

class Tests(unittest.TestCase):

    def test_a_uses_b(self):
        a = create_a()
        b = create_b()
        a.b = b
        self.assertIs(b.a, a)

    def test_b_uses_a(self):
        a = create_a()
        b = create_b()
        b.a = a
        self.assertIs(a.b, b)

实例化TestSuiteTestCase我自己绕过测试加载器导致了一个错误,因为它需要一个名为runTest.

结果是这样的:

class Tests(unittest.TestCase):

    def __init__(self, create_a, create_b):
        super().__init__()
        self.create_b = create_b
        self.create_a = create_a

    def test_a_uses_b(self):
        a = self.create_a()
        b = self.create_b()
        a.b = b
        self.assertIs(b.a, a)

    def test_b_uses_a(self):
        a = self.create_a()
        b = self.create_b()
        b.a = a
        self.assertIs(a.b, b)


class TestPair1(Tests):
    def __init__(self):
        super().__init__(create_a1, create_b1)


class TestPair2(Tests):
    def __init__(self):
        super().__init__(create_a2, create_b2)
于 2017-03-16T13:02:13.770 回答