我有一个Python单元测试,其中一些测试具有相同的类型对象测试。一个测试类的基本概要是:
class TestClass(unittest.TestCase):
def setup(self):
...
def checkObjects(self, obj):
for i in [...values...]:
self.assertEqual(starttags(i,obj), endtags(i,obj))
def testOne(self):
#Get object one.
checkObjects(objone)
def testAnother(self):
#Access another object.
checkObjects(another)
... various tests for similar objects.
虽然它是模块化的,但我注意到任何失败都会产生类似AssertionError的错误:number!= anothernumber,以及产生错误的代码行self.assertEqual(starttags(i,obj), endtags(i,obj))
。如果我列出了测试而不是放置for循环,我会有类似的东西:
self.assertEqual(starttags(value1,obj), endtags(value1,obj))
self.assertEqual(starttags(value2,obj), endtags(value2,obj))
其中显示哪种情况确实导致错误,但是复制粘贴代码,我认为通常不推荐使用。我最近发现了一个问题,当一个贡献者重新编写了一个更 clean 单元测试时,遗憾的是它会在断言失败时提供很少的调试信息。那么,这些案例中最好的做法是什么?类似于元组列表的东西,使用assertEquals进入for循环是“更干净”,但在不同行上使用不同值的复制粘贴可以提供有用的堆栈跟踪。
答案 0 :(得分:7)
如果通过 cleaner 意味着更少的代码,那么这种 clean 代码并不总是更多可读代码。事实上,它通常不太可读(特别是当你回到它时)。您可以随时使用花哨的重构,但您需要知道何时停止。从长远来看,使用更明显,更简单的代码总是比尝试挤出少一行代码以获得人工增益更好 - 而不仅仅是单元测试。 / p>
单元测试符合他们自己的规则。例如,它们通常允许不同于常规代码标准所说的命名约定,您几乎不会记录它们 - 它们是您的代码库的特殊部分。此外,重复代码并不常见。实际上,通常会有许多类似的小型测试。
目前,即使在编写测试阶段,您的测试仍然令人困惑 - 想象一下从现在开始的3个月后回到该代码。想象一下,由于别人在某些其他地方进行某些更改而导致其中一项测试失败。它不会变得更好。
以这样的方式设计您的测试,当其中一个测试中断时,您立即知道为什么这样做以及在哪里。不仅如此 - 以这样的方式设计它们,你可以在眨眼间告诉他们正在做什么。在测试代码中有 for循环, ifs 以及基本上任何其他类型的控制流机制(或过于广泛的重构),通常会导致一个问题引起你的注意 - 我们在这做什么? 这是你不想发现的问题。
用比我更聪明的人的话总结这篇冗长的帖子:
任何傻瓜都可以编写计算机可以理解的代码。优秀的程序员编写人类可以理解的代码。
-Martin Fowler等,Refactoring: Improving the Design of Existing Code, 1999
帮自己一个忙,坚持这条规则。
答案 1 :(得分:0)
使用nosetests,它可以让你的测试变得更加清洁:
#!/usr/bin/python
def test_one():
for i in [...]:
assert xxx(i) == yyy
def test_two():
...