在解决这种情况时,我遇到了麻烦。
假设我在Python中有一个单元测试,它将测试可迭代对象中的多个元素。由于在内存中构建此可迭代方法非常昂贵,因此我只想通过setUpClass
方法构建它。然后,在每个测试中,我想依次将可迭代对象中的每个元素传递给测试,我可以使用context manager and the subTest
method。很好。
以下代码是一个模拟测试案例的示例,完全按照我的描述进行操作:
import unittest
class NumberTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.numbers = []
for x in range(1000):
cls.numbers.append(x)
@classmethod
def tearDownClass(cls):
del cls.numbers
def test_number_is_even(self):
for n in self.numbers:
with self.subTest(current_number=n):
self.assertEqual(n % 2, 0)
def test_number_is_odd(self):
for n in self.numbers:
with self.subTest(current_number=n):
self.assertEqual(n % 2, 1)
def test_number_is_positive(self):
for n in self.numbers:
with self.subTest(current_number=n):
self.assertTrue(n > 0)
def test_number_is_negative(self):
for n in self.numbers:
with self.subTest(current_number=n):
self.assertTrue(n < 0)
if __name__ == '__main__':
unittest.main()
给我带来麻烦的是,每种测试方法都重复行for n in self.numbers: with self.subTest(current_number=n): . . .
。有什么办法可以避免这种情况?我知道我可以将所有self.assert
语句简单地合并为一个方法,但是这违背了首先针对不同方面进行不同测试的目的。
在我看来,“理想”的解决方案是以某种方式yield
迭代中的值(也许通过setUp
方法?不知道),然后将这些值传递给每个测试方法产生下一个。但我不知道如何实际执行此操作,尤其是因为它涉及到上下文管理器...是否有人有其他解决方案,或者根本没有解决方法?
答案 0 :(得分:1)
一个简单的解决方案是将for
和with
语句外包给装饰器。不过,每个测试用例仍然需要一行:
import functools
import unittest
class NumberTest(unittest.TestCase):
# ...
def for_each_number(test_func):
@functools.wraps(test_func)
def decorated(self):
for n in self.numbers:
with self.subTest(current_number=n):
test_func(self, n)
return decorated
@for_each_number
def test_number_is_even(self, n):
self.assertEqual(n % 2, 0)
@for_each_number
def test_number_is_odd(self, n):
self.assertEqual(n % 2, 1)
# ...
当然,这不会像理想解决方案那样在迭代过程中运行一次。为此,您需要装饰整个课程。使用parameterized库中的@parameterized_class
装饰器似乎可以做到这一点。不过,我从来没有独自使用过这个装饰器。