Mockito示例
在本程序中,我们将研究Mockito,Java中的完整框架,以创建测试double或者模拟。
介绍
Mockito是Java中的一个开源映射框架,提供了创建测试双打的简单方法,也称为进一步的写作。
在Mockito中,我们通过将虚拟函数添加到可用于单元测试中的模拟接口来模拟行为,而不是实现。
本程序将开始使用Mockito API。
Mockito拥有一群有效的开发人员,拥有强大的社区支持,并积极维护,最后一个Mockito版本是2.9.0版。
术语
在使用Mockito迁移到工作示例之前,我们应该知道可以在Mockito中创建和使用的不同类型的测试对象。
- 虚拟:这是一个仅用于编译代码的对象,并且没有与传递给函数的参数相关联的业务逻辑。
- Fake:这是一个具有实现但不准备生产的对象,如H2内存数据库。
- Stub:这是一个对象,它具有在测试期间进行的方法执行的预定义答案。
- 模拟:这是一个对象,它具有预定义的方法对测试期间执行的方法答案,并记录了这些执行的期望。
- spy:这是一个类似于存根的对象,但它们还记录了它们的执行方式。
添加到ClassPath,使用Maven
添加Mockito依赖于项目的最佳方法是使用Maven构建系统。
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-all --> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-all</artifactId> <version>1.10.19</version> </dependency>
此依赖性足够简单,不会带来任何其他或者冗余库。
请参阅此处获取最新版本的库。
使用Mockito API.
我们将立即开始使用测试(SUT)的示例系统,一个简单的一个才能开始。
Mockito中有几种方法来创建模拟对象。
喜欢:
- 使用@Mock注释
- 使用静态模拟()方法
当我们使用@Mock注释时,我们必须触发创建注释对象。
让我们使用示例演示此注释的使用:
import static org.mockito.Mockito.*; public class TestWithMockito { @Test public void testQuery() { //arrange Iterator iterator = mock(Iterator.class); when(iterator.next()).thenReturn("Hello").thenReturn("World"); //act String result =iterator.next() + " " +iterator.next(); //assert assertEquals("Hello World", result); } }
使用静态模拟方法时,我们无需将@runwith(mockitojunitrunner.class)或者mockitrule放入。
在上面的例子中完成了很多。
让我们一步一步一步发生了什么。
- 我们使用迭代器类开始模拟()。它告诉mockito模拟迭代器类实例。
- 接下来,当调用另一个类的方法时,我们使用Mockito静态改变结果。这将确保在调用方法时迭代器的类返回特定数据。
- 以下是一个示例代码,调用调用当语句时的迭代器方法。
- 在最后一行,我们验证结果。
另请注意,在开始时,我们在类Mockito类中静态导入所有方法。
这允许我们使用验证和查询等方法。
现在,我们将使用@Mock注释使用的另一个示例。
当我们使用@Mock注释时,我们需要使用@runwith(mockitojunitrunner.class)或者mockitrule。
与@runwith(mockitojunitrunner.class)
在此测试中,我们将根据参数从模拟列表返回值。
例如,如果list.get(1)被调用,则应返回"第二个元素"
package org.igi.theitroad; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.when; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; @RunWith(MockitoJUnitRunner.class) public class TestWithMockAnnotation { @Mock private List list; @Test public void testQuery() { //arrange when(list.get(1)).thenReturn("Second element"); when(list.get(2)).thenReturn("Third element"); String secondElementFromList=list.get(1); //assert assertEquals("Second element", secondElementFromList); } }
用mockitrule
在此示例中,我们将从列表中返回相同的值,而不论参数如何。
例如,如果我们调用list.get(1)或者list.get(3),它将返回相同的值:"默认元素"
package org.igi.theitroad; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.*; import java.util.List; import org.junit.Rule; import org.junit.Test; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; public class TestWithMockitoJUnitRule { @Rule public MockitoRule rule = MockitoJUnit.rule(); @Mock private List list; @Test public void testQuery() { //arrange when(list.get(anyInt())).thenReturn("Default element"); String tenthElement=list.get(9); //assert assertEquals("Default element", tenthElement); } }
Mockito的最佳实践
单元测试的共同理解是测试软件的最小可能部分,特别是一种方法。
实际上,我们没有测试方法;相反,我们测试一个逻辑单元或者系统的行为。
可读性
JUnit测试写入测试逻辑单元。
测试方法名称应该描绘测试的意图,以便读者可以理解正在测试的内容,例如条件和期望或者动作。
良好的测试方法名称可以是:
- scompl_not_register_a_null_user()
- shangut_throw_exception_when_a_null_user_is_registered()
打破一切
一个极端的编程概念是测试可能破坏的一切。
这意味着尝试所有不同的输入组合,以确保我们不会错过任何可能导致该类生成错误的组合。
忽略琐碎的测试
写琐碎的junits(例如,为吸气器和setter)大多是浪费时间和金钱。
我们没有奢侈品来写入无限测试,因为它可以吃我们的开发时间,应用程序构建时间,降低测试可维护性。
如果我们开始写入Getter/Setter的测试,我们可能会错过更有用的测试用例。
远离调试
当我们发现一个错误时,我们发现一个常见的做法是开始调试应用程序 - 停止执行此操作。
相反,添加更多测试来打破代码;这将丰富测试套件并改进系统文档。
因此,无论如何,在开始调试之前,创建一个(集成)测试,可再现问题,然后调试它。
这将缩小问题,为最低可能的单位创建一个单元测试,并保持测试的未来参考。