单元测试中的代码重用?
我经常听到有人说,测试应该简单、易于维护、直接明了,但在单元测试中,代码的可重用性又该如何呢?
我们来举个例子:
def test_some_1():
...some code
def test_some_2():
...code repeated from test_some_1
把这两个测试中重复的代码放到一个函数里,这样可以集中处理必要的断言,这样不是更好吗?
我和一些程序员对此有过争论,他们不同意,认为测试应该简单,不应该追求代码的可重用性。他们的理由是,在django控制台中,断言失败的地方不太明显,因为断言是在函数里。不过我不同意这个观点,因为如果用nose工具的话,你可以看到测试的名称和错误追踪信息,虽然那些人又反驳说,测试可以单独运行而不使用nose(这样就看不到那些详细信息了)。
你们怎么看?
- 在单元测试中使用代码的可重用性好不好?
- 如果可重用性可以或必须使用,那怎么解决关于定位断言的问题呢?
2 个回答
0
正如你的同事们所说,你应该让你的测试尽量简单。这样做有几个原因,最重要的是你想避免在测试中写复杂的逻辑。如果你把测试写得“聪明”,那么它们往往会包含和你想测试的代码相同或相似的逻辑。这就意味着你可能在两个地方都犯同样的错误,从而错过你想要发现的bug。
另一个原因是,你希望你的测试能够作为你要测试的代码的文档。如果测试的执行路径复杂,涉及很多函数和逻辑,那么理解起来就会变得不那么容易。在理想情况下,你只需看一下测试,就能明白生产代码是如何工作的。
7
代码质量中最重要的因素,比如清晰度和可读性,对于测试代码来说同样重要。如果代码重复能让阅读变得更简单,那就应该这样做,不管你写的是测试代码还是其他代码,反之亦然。
举个例子,我写的一个包里有一个函数:
def _test_vector(self, a, b, c):
# test the function with parameter values a, b, c
# several asserts here to verify output of function tested
这个函数让我可以这样写所有的测试向量:
def test_vector1(self):
self._test_vector(a=42, b=5, c="blah)
我认为这样做提高了清晰度,因为每个测试只包含与该测试相关的信息。
定位断言(assertions)应该总是很简单。即使是 unittest
也会给你一个错误追踪信息,如果你的测试设置没有指向某个特定的断言,那你在调试测试失败时会很困难,所以一定要换成更合理的方式。