Background:
Test Case也是代码,但好像又跟真实逻辑中的代码有所不同,那么不同在哪里呢?有这些不同会导致评价测试用例的标准有什么独特之处呢?
本文试图回答上述两个问题:
- Test Case作为代码与业务逻辑代码的异同
- Test Case评价的标准
Test Case与业务代码的评价标准有所不同
DAMP (“Descriptive and Meaningful Phrases”) V.S. DRY(“Don’t Repeat Yourself”)
下面的测试用例遵循了DRY原则(“Don’t Repeat Yourself”),DRY鼓励代码重用而不是复制,例如通过提出helper方法或者使用循环。但这是一个好的测试用例吗?1
2
3
4
5
6
7
8
9
10
11
12def setUp(self):
self.users = [User('alice'), User('bob')] # This field can be reused across tests.
self.forum = Forum()
def testCanRegisterMultipleUsers(self):
self._RegisterAllUsers()
for user in self.users: # Use a for-loop to verify that all users are registered.
self.assertTrue(self.forum.HasRegisteredUser(user))
def _RegisterAllUsers(self): # This method can be reused across tests.
for user in self.users:
self.forum.Register(user)
尽管测试的主体还是很简洁的,但读者需要在脑海里做一些运算才能理解这个测试用例的意图,例如,通过从setUp()到_RegisterAllUsers()跟踪self.users的使用流程才能真正理解用例的含义。因为测试用例没有测试用例来保证了,TA需要保证人能够直观的分析其正确性,即使是这么搞会带来很多的重复代码。这也意味着尽管DRY是生产代码的最佳实践,但DRY原则是不完全适用于测试用例的编写的。
在测试用例中我们可以使用DAMP(“Desciptive and Meaningful Phrases”),DAMP强调可读性高于唯一性。尽管应用该原则会导致代码重复(例如,重复了简单代码),但这使得测试用例更容易被认为是”明显没问题”。让我们就这上面的case,用DAMP原则改写一下:
1 | def setUp(self): |
注意,DRY原则在测试中还是有其意义的;例如,使用一个helper方法来创建value object可以从测试用例的主体逻辑中移除过多的细节,从而提升清晰度。理想情况下,测试用例可以做到既可读又没有重复,但有些时候需要在二者之间做个取舍。当写测试用例时,如果碰到了需要在DRY与DAMP之间做个选择,首选DAMP。
业务代码有测试用例保障,测试用例没有测试用例保障
如上文中提到的,业务代码有测试用例而测试用例没有测试用例了。这样的差异会导致二者的最终分化。
即由于业务代码有测试用例,因此TA的组织形式可以相对复杂,应用各种设计模式,采用DRY原则保证避免散弹式修改,因为TA明白,其正确性是依赖于测试用例保证的,而不是依赖人眼保证的。人在业务代码的正确性保证方面做的是没明显问题
测试用例则不然,由于没有测试用例的测试用例保障,因此其正确性完全依赖于人眼保证,即Review测试用例需要能够做到明显没问题。
因此,测试用例越容易被看懂,越容易判断正确性,越好。
Test Case评价的标准
测试用例稳定性
TBD…
测试用例可读性及明显没问题
TBD…
参考文献
https://testing.googleblog.com/2019/12/testing-on-toilet-tests-too-dry-make.html