我写的JUnit测试用例3个用途:
- 为了确保我的代码满足所有所需的功能,在所有(或大部分)的输入组合/值。
- 为了确保我可以改变的执行情况,并依靠JUnit测试案例来告诉我,我所有的功能还是满意的。
- 由于所有用例我的代码处理一个文档,并作为重构一个规范 - 应该代码以往任何时候都需要重写。 (重构代码,如果我的JUnit测试失败 - 你可能错过了一些用例)。
我不明白为什么或什么时候Mockito.verify()
应该被使用。 当我看到verify()
被调用时,它告诉我,我的JUnit是知悉的执行。 (从而改变了我的实现会打破我的jUnits,即使我的功能并没有受到影响)。
我在找:
应该是什么的适当的使用准则Mockito.verify()
它是从根本上纠正jUnits要注意的,还是紧耦合的,被测类的实现?
如果类A的合同包括它调用C类的对象的方法B中的事实,那么你应该通过使C类型的模拟和验证方法B已经呼吁对此进行测试。
这意味着,类A的合同有足够的细节,它谈论类型C(这可能是一个接口或一个类)。 所以,是的,我们正在谈论规范的水平,超越只是“系统要求”,并在某种程度上对描述的实施。
这是正常的单元测试。 当你的单元测试,你要确保各单位在做“正确的事”,这通常将包括其与其他单位的相互作用。 “单位”这里可能意味着类或更大的应用程序的子集。
更新:
我觉得这并不适用于只是为了验证,但磕碰为好。 只要你存根合作者类的方法,你的单元测试已经成为,在某种意义上,依赖于实施。 这是一个在单元测试的性质那种是如此。 由于是的Mockito高达约磕碰,因为它是验证,事实上,你正在使用的的Mockito都意味着你要跨越这种依赖的运行。
根据我的经验,如果我改变一类的实现,我经常要改变它的单元测试,以配合实施。 通常情况下,虽然,我不会有改变有该类的什么单位测试清单; 当然,除非该变化的原因是,我没能更早测试条件的存在。
因此,这是单元测试是什么。 不从这样的协作者类的使用方式依赖遭受考验确实是一个子系统测试或集成测试。 当然,这些被频繁写入使用JUnit过,而且经常涉及使用嘲讽。 在我看来,“JUnit的”是一个可怕的名字,对于一个产品,让我们生产各种不同类型的测试。
大卫的答案当然是正确的,但并没有完全解释为什么你会想这个。
基本上,当单元测试你在隔离测试的功能单位。 你测试输入是否会产生预期的输出。 有时候,你必须测试的副作用以及。 简而言之,验证可以让你做到这一点。
例如你有一个应该存储使用DAO东西业务逻辑位。 你可以做到这一点使用一个集成测试实例化的DAO,钩起来的业务逻辑,然后在数据库捅身边,看是否得到了保存预期的东西。 这不是一个单元测试了。
或者,你可以嘲笑的DAO,并验证它被调用在你希望的方式。 随着你的Mockito可以验证的东西被调用时,它是如何经常被称为,甚至使用的参数匹配器,以确保它被调用以特定的方式。
像这样的单元测试的另一面的确是你绑测试执行这使得重构有点困难。 在另一方面,一个好的设计气味的代码才能正确行使它的量。 如果你的测试需要非常长的,大概什么是错的设计。 所以有很多的副作用/复杂的相互作用需要被测试的代码可能不是一个好东西。
这是很大的问题! 我认为它的根本原因就是下面,我们使用JUnit不仅进行单元测试。 所以问题应该splited起来:
- 我应该使用Mockito.verify()在我的集成 (或任何其他比单元高测试)测试?
- 我应该在我的黑盒单元测试使用Mockito.verify()?
- 我应该在我的白盒单元测试使用Mockito.verify()?
所以,如果我们忽略比单元高测试,这个问题可以改写“ 使用白盒单元测试与Mockito.verify()创建单元测试和我能实现之间有很大的情侣,我可以做一些”灰箱“单元测试和拇指什么我应该为此使用的规则 ”。
现在,让我们通过这一切一步一步的。
* -如果我在集成 (或任何其他比单元高测试)测试使用Mockito.verify()*我想答案显然是否定的,而且你不应该使用嘲笑这个? 您的测试应尽可能接近实际应用成为可能。 您正在测试完整使用情况下,应用的不是孤立的一部分。
* 黑盒 VS 白盒单元测试*如果您正在使用黑箱方法你真的做什么,你提供(所有等价类)输入, 状态和测试,你会收到预期的输出。 在使用一般的嘲笑的这种做法是证明(你只是模仿,他们正在做正确的事情,你不希望对其进行测试),但调用Mockito.verify()是多余的。
如果使用的是白盒的方法是什么,你真的做,你测试你的单位的行为 。 在这种方法中调用到Mockito.verify()是必不可少的,你应该确认你的单位行为就像你期待。
大拇指对规则灰盒测试的问题与白盒测试是它产生高的耦合。 一个可能的解决办法是做灰盒测试,不用白箱测试。 这有点黑与白箱测试的组合。 你真的测试你的单位的行为就像在白盒测试,但一般你把它实现不可知时可能 。 如果可能的话,你只会使暗箱情况类似的支票,而是断言输出是什么是你的预计。 所以,你的问题的实质是,当它是可能的。
这是真的很难。 我没有一个很好的例子,但我可以给你的例子。 在与equals()方法VS equalsIgnoreCase上面提到的情况下,(),你不应该调用Mockito.verify(),就断言输出。 如果你不能做到这一点,你的代码分解成更小的单位,直到你能做到这一点。 在另一方面,假设你有一些@Service和你书面方式@ Web的服务,本质上是在你的@服务外包程序 - 它代表所有来电到@Service(和做一些额外的错误处理)。 在这种情况下打电话给Mockito.verify()是必不可少的,你不应该重复所有的检查,你做的@Serive的,核实你打电话到@Service与正确parammeter列表就足够了。
我必须说,你是从传统方法的观点完全正确:
- 如果你第一次创建(或修改)应用程序的业务逻辑 ,然后用覆盖它(通过)的测试 (测试最后一种方法 ),那么这将是非常痛苦和危险,让测试一无所知如何您的软件作品,比其他检查输入和输出。
- 如果你正在练习一个测试驱动的方法 ,那么你的测试是第一次写入,改变并反映用例您的软件的功能。 实现取决于测试。 有时意味着,要在一些特殊的方式,如要实现你的软件依赖于其他一些组件的方法,甚至把它的时间特定的量。 这就是Mockito.verify()就派上用场了!
需要记住的是很重要的,不存在普遍的工具。 该类型的软件,它的大小,公司目标和市场情况,团队技能和许多其他的事情影响上接近你的特殊情况下使用的决定。
至于有些人说
- 有时候,你没有直接输出上,您可以断言
- 有时候,你只需要确认你的测试方法发送正确的间接输出,它的合作伙伴(你所嘲笑)。
关于你提到的关于重构使用嘲笑/存根/间谍时,即预期有所突破时,你的测试问题。 我的意思是,根据定义,而不是关于具体的实施如的Mockito。 但是你可以这样想-如果你需要做的是将创建你的方法的工作方式发生重大变化一个重构,这是一个好主意,做一个TDD的方式,这意味着你可以先改变你的测试定义新的行为(将未通过测试), 然后做的更改,并将再次通过了测试。