我开始在我的项目中练习TDD,作为背景,它还包含遗留代码。我们使用Mockito作为模拟框架并遵循Spring MVC方法。
有时,Service
类使用许多不同的DAO
对象作为@Autowired
属性实现。这些服务中有简单的方法,例如completeTransaction
。
completeTransaction
将使用许多DAO
个对象来完成其职责
但是,在执行这些操作时,该方法需要调用不同的DAO
来获取和更新事务,获取业务流程ID,获取挂起的事务(并保存其更新)。这意味着测试此方法的单元使我添加了许多@Mock
属性。我需要在测试实际完成之前设置模拟对象以测试某个条件。
这看起来像代码味道,对我来说,几乎感觉测试是确保代码的实现,而不仅仅是它的合同。同样,在不模仿依赖关系的情况下,测试用例将不会运行(由于NPE和其他因素)。
我可以遵循什么策略来清理这样的代码? (虽然我无法真正提供问题的实际源代码)。我认为一种可能性就是使用类似(" getPendingOperations"" advanceBusinessProcess")等方法设置外观类。然后我可以模拟一个依赖。但后来我认为,在所有其他类似情况的课程中,我需要做同样的事情,然后我害怕最终得到很多帮助"课程只是为了更清洁的测试。
先谢谢你。
答案 0 :(得分:3)
我觉得当你发现自己有太多嘲笑时,你会想做两件事。这些并不是必须的,但您可能会觉得它们很有帮助。
1)尝试使您的方法和类更小。我认为清洁代码说有两个规则,类应该很小。而那些类应该小于那个。这有一定道理,因为随着您测试的单元(方法和类)变小,依赖项也会变小。你当然会得到更多的测试,但是每次测试都会有更少的设置。
2)看看得墨忒耳定律(https://en.wikipedia.org/wiki/Law_of_Demeter)。有一堆规则,但基本上,你想避免长串的属性/方法调用。 objA = objB.propertyA.SomeMethod().propertyC;
如果您需要模拟所有这些对象只是为了获得objA,那么您将进行大量设置。但是如果你可以用objA = objB.newProperty;
替换它,那么你只需要模拟objB,它就是一个属性。
这些都不是银子弹,但希望你可以在项目中使用其中的一些想法。
答案 1 :(得分:0)
如果单元测试正在测试completeTransaction
方法,那么您必须模拟它所依赖的所有内容。由于您使用的是Mockito,因此您可以使用verify
确认调用了正确的模拟方法,并以正确的顺序调用它们。
如果单元测试正在测试调用completeTransaction
方法的内容,那么只需模拟completeTransaction
方法。
如果这是您的类层次结构:
class A -> class B -> class C
(其中 - >是“取决于”)
在A类的单元测试中,仅模拟B类。
在B类的单元测试中,只模拟C类。