在python中提供测试数据

jin*_*ski 10 python unit-testing

如何针对大量不同的数据运行相同的测试?我希望报告所有失败.

例如:

def isEven(number):
    return True # quite buggy implementation

data = [ 
    (2, True), 
    (3, False), 
    (4, True),
    (5, False),
]

class MyTest:
   def evenTest(self, num, expected):
       self.assertEquals(expected, isEven(num))
Run Code Online (Sandbox Code Playgroud)

我找到的解决方案仅在第一次失败时引发错误:http: //melp.nl/2011/02/phpunit-style-dataprovider-in-python-unit-test/

如何运行测试报告所有故障?

mod*_*sto 11

如果您使用的是pytest,您可以这样做:

import pytest

def is_even(number):
    return True # Wuite buggy implementation

@pytest.mark.parametrize("number, expected", [
    (2, True),
    (3, False),
    (4, True),
    (5, False)
])
def test_is_even(number, expected):
    assert is_even(number) == expected
Run Code Online (Sandbox Code Playgroud)

你会得到类似(缩短)的东西:

import pytest

def is_even(number):
    return True # Wuite buggy implementation

@pytest.mark.parametrize("number, expected", [
    (2, True),
    (3, False),
    (4, True),
    (5, False)
])
def test_is_even(number, expected):
    assert is_even(number) == expected
Run Code Online (Sandbox Code Playgroud)

  • 也许在提供其他答案时标记参数化不存在,但这在这里感觉像是正确的答案。 (2认同)

Sve*_*ach 7

一种解决方案是为每个条目制作不同的测试用例实例data:

class MyTest(unittest.TestCase):
    def __init__(self, num, expected):
        unittest.TestCase.__init__(self, "evenTest")
        self.num = num
        self.expected = expected
    def evenTest(self):
        self.assertEqual(self.expected, isEven(self.num))
Run Code Online (Sandbox Code Playgroud)

对于unittest知道如何构建测试的情况下,增加一个load_tests()功能,你的模块:

def load_tests(loader, tests, pattern):
    return unittest.TestSuite(MyTest(num, expected)
                              for num, expected in data)
Run Code Online (Sandbox Code Playgroud)


Anu*_*yal 7

你应该使用py.test,我认为unittest模块是从junit一味地复制的,无论如何你可以像这样破解你的方式

import unittest

data = [ 
    (2, True), 
    (3, False), 
    (4, True),
    (5, False)]

# this should be imported from a separate module.
def isEven(number):
    return True # quite buggy implementation

def create_test_func(num, expected):
    def _test_func(self):
        self.assertEqual(expected, isEven(num))
    return _test_func

class TestIsEven(unittest.TestCase):

    pass

# pyunit isn't pythonic enought use py.test instead
# till then we rely on such hackery
import new
for i, (num, expected) in enumerate(data):
    setattr(TestIsEven, 'test_data_%d'%i, create_test_func(num, expected))

if __name__ == "__main__":
    unittest.main()
Run Code Online (Sandbox Code Playgroud)

输出是:

.F.F
======================================================================
FAIL: test_data_1 (__main__.TestIsEven)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "untitled-1.py", line 15, in _test_func
    self.assertEqual(expected, isEven(num))
AssertionError: False != True

======================================================================
FAIL: test_data_3 (__main__.TestIsEven)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "untitled-1.py", line 15, in _test_func
    self.assertEqual(expected, isEven(num))
AssertionError: False != True

----------------------------------------------------------------------
Ran 4 tests in 0.000s

FAILED (failures=2)
Run Code Online (Sandbox Code Playgroud)

使用这种方法,您可以添加更多细节,例如在失败时打印调试信息等


mou*_*uad 5

你可能正在寻找这样的东西:

import unittest


def is_even(number):
    return True # Quite buggy implementation


class TestCase(unittest.TestCase):
    def setUp(self):
        self.expected_output = [
            (2, True),
            (3, False),
            (4, True),
            (5, False)
        ]

    def test_is_even(self):
        real_res = []

        for arg, _ in self.expected_output:
            real_res.append((arg, is_even(arg)))

        msg_error = '\nFor %s Expected %s Got %s'
        msg = []
        for res1, res2 in zip(real_res, self.expected_output):
            if res1[1] != res2[1]:
                msg.append(msg_error % (res1[0], res1[1], res2[1]))


        self.assertEqual(real_res, self.expected_output, "".join(msg))


if __name__ == '__main__':
    unittest.main()
Run Code Online (Sandbox Code Playgroud)

输出:

import unittest


def is_even(number):
    return True # Quite buggy implementation


class TestCase(unittest.TestCase):
    def setUp(self):
        self.expected_output = [
            (2, True),
            (3, False),
            (4, True),
            (5, False)
        ]

    def test_is_even(self):
        real_res = []

        for arg, _ in self.expected_output:
            real_res.append((arg, is_even(arg)))

        msg_error = '\nFor %s Expected %s Got %s'
        msg = []
        for res1, res2 in zip(real_res, self.expected_output):
            if res1[1] != res2[1]:
                msg.append(msg_error % (res1[0], res1[1], res2[1]))


        self.assertEqual(real_res, self.expected_output, "".join(msg))


if __name__ == '__main__':
    unittest.main()
Run Code Online (Sandbox Code Playgroud)

  • @jinowolski:没错,很高兴我们可以根据需要自定义错误消息,我编辑了我的答案,我不知道这是否适合您。 (3认同)
  • @Anurag:IMO 应该是什么,一个(简单的)功能一个测试,即使我们想拆分测试,至少它们都应该在一个测试用例中弄清楚,我无法想象将它拆分成更多一个测试用例,特别是如果这只是一个大包的一部分,但这只是我的拙见:) (3认同)