mockito实战
一. 简介
Mockito是一个模拟测试框架,可以让你用优雅,简洁的接口写出漂亮的单元测试。Mockito可以让单元测试易于可读,产生简洁的校验错误。
二. 应用场景
假设现在要测试method A, method A里面又依赖Method B、Method C、Method D,而依赖的这3个method又不好去构建(如ObsClient需要真实AK SK,HttpClient需要构建客户端与服务器,Database相对好构建,但是假设Method C只是从table1、table2联合查询,你还得分别往table1、table2 insert数据,很繁琐),这时候可以考虑Mockito进行优雅测试,当然如果你想去构建真实的测试场景,未免有点舍本逐末了。
三. 使用案例
1. 引入依赖
由于springboot中已经集成了mockito,因此我们只需要加入下面这个依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
2. 创建依赖类
这个类我们可以理解最终要测试的目标,我们定义了getRandom()方法,这个方法我们指定随机返回0或1。
@Service
public class RandomService {
public int getRandom(){
return new Random().nextInt(2);
}
}
3. 创建被测类
模拟调用依赖类中的getRandom()方法
@Service
public class UseRandomService {
// 注入目标类
@Autowired
private RandomService randomService;
public String hello() {
int status = randomService.getRandom();
if (status == 0) {
return "Hey";
}
else if (status == 1) {
return "Hello";
}
else {
return "未知状态";
}
}
}
4. 编写测试类
public class UseRandomServiceTest {
@Mock
private RandomService randomService;
@InjectMocks
private UseRandomService useRandomService;
@Before
public void init(){
MockitoAnnotations.openMocks(this);
}
@Test
public void testRandom() {
when(randomService.getRandom()).thenReturn(0);
Assert.assertEquals("Hey", useRandomService.hello());
when(randomService.getRandom()).thenReturn(1);
Assert.assertEquals("Hello", useRandomService.hello());
}
}
说明:之所以这块备注依赖类和被测类是为了方便讲解这里测试类中的注解,常用的注解有@Mock和@InjectMock,另外还有MockitoAnnotations.openMocks(this)方法。下面我们做详细说明
5. 解析
1. @Mock
mock对象:一般是被测对象依赖的对象(就是我们代码中的RandomService )。
使用时用@Mock注解作用在该对象上即可使用该注解时,要使用MockitoAnnotations.openMocks(this)方法,让注解生效,也可以在类上加上@RunWith(MockitoJUnitRunner.class)注解
@Before
public void init(){
MockitoAnnotations.openMocks(this);
}
@RunWith(MockitoJUnitRunner.class)
public class UseRandomServiceTest {
如果不开启注解,就会报空指针异常。
java.lang.NullPointerException
at com.tomato.tomatocenter.mockit.UseRandomServiceTest.testRandom(UseRandomServiceTest.java:31)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
2. @Spy
被@Spy的对象,调用其方法时默认会走真实方法。mock 对象不会。
3. @InjectMocks
被@InjectMocks注解的对象就是要被我们测试的对象,它会被自动的实例化。且其包含的成员变量会被相应的@Mock或@Spy注解的对象自动赋值
以上案例只是讲解了一次对mockit的使用,了解更多详情请参考Mockito中文文档