单元测试和太多嘲笑

时间:2014-01-20 15:57:12

标签: java unit-testing

我开始在我的项目中练习TDD,作为背景,它还包含遗留代码。我们使用Mockito作为模拟框架并遵循Spring MVC方法。

有时,Service类使用许多不同的DAO对象作为@Autowired属性实现。这些服务中有简单的方法,例如completeTransaction

completeTransaction将使用许多DAO个对象来完成其职责

  • 更新并保存交易
  • 推进业务流程
  • 结束其他待处理的操作

但是,在执行这些操作时,该方法需要调用不同的DAO来获取和更新事务,获取业务流程ID,获取挂起的事务(并保存其更新)。这意味着测试此方法的单元使我添加了许多@Mock属性。我需要在测试实际完成之前设置模拟对象以测试某个条件。

这看起来像代码味道,对我来说,几乎感觉测试是确保代码的实现,而不仅仅是它的合同。同样,在不模仿依赖关系的情况下,测试用例将不会运行(由于NPE和其他因素)。

我可以遵循什么策略来清理这样的代码? (虽然我无法真正提供问题的实际源代码)。我认为一种可能性就是使用类似(" getPendingOperations"" advanceBusinessProcess")等方法设置外观类。然后我可以模拟一个依赖。但后来我认为,在所有其他类似情况的课程中,我需要做同样的事情,然后我害怕最终得到很多帮助"课程只是为了更清洁的测试。

先谢谢你。

2 个答案:

答案 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类。