Spring 应用进行Mockito 单元测试详解
个人理解
通过mockito给程序设定一个预期值,然后通过mockito仿真执行程序,看执行逻辑输出是否符合预期的结果。主要用于检测逻辑是否正确。由于不是真的执行,因此会隔离真实环境。无法测试底层调用或者sql是否存在问题。
mockito 资源
官网: http://mockito.org
API文档:http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html
项目源码:https://github.com/mockito/mockito
依赖
junit
junit
4.12
test
org.mockito
mockito-all
1.10.19
test
org.mockito
mockito-core
3.3.3
test
org.powermock
powermock-module-junit4
1.6.5
test
org.powermock
powermock-api-mockito
1.6.5
test
注解
注解 | 作用 | 例子 |
---|---|---|
@PowerMockIgnore | 忽略一些模块 | @PowerMockIgnore("javax.management.*") |
@PrepareForTest | mock静态类 | @PrepareForTest({NumberUtils.class}) |
@RunWith | 启动注解,使用什么来运行程序 | @RunWith(MockitoJUnitRunner.class) |
注意事项
- @PowerMockIgnore("javax.management.*")
由于PowerMock的工做原理便是使用自定义的类加载器来加载被修改过的类,从而达到打桩的目的,使用Powermock后会提示classloader错误,所以待测试类中使用到了XML解析相关的包和类,那么测试类前一样须要增长@PowerMockIgnore({"org.xml.", "javax.xml."}),消除类加载器引入报错。
- @PrepareForTest({NumberUtils.class})
把静态方法mock掉,模拟调用静态方法,返回一个给定的值。
PowerMockito.mockStatic(NumberUtils.class);
when(NumberUtils.change()).thenReturn("123");
- 调用无返回的方法
PowerMockito.doNothing().when(casService).addSupplier(anyLong(), any(ServiceKey.class));
连续调用
@Test(expected = RuntimeException.class)
public void continuousCallTest() {
// 模拟连续调用返回指望值,若是分开,则只有最后一个有效
PowerMockito.when(exampleServiceMock.aTest()).thenReturn("1");
PowerMockito.when(exampleServiceMock.aTest()).thenReturn("2");
PowerMockito.when(exampleServiceMock.aTest()).thenReturn("3");
PowerMockito.when(exampleServiceMock.aTest()).thenReturn("4");
PowerMockito.when(exampleServiceMock.aTest()).thenReturn("1").thenReturn("2").thenThrow(new RuntimeException());
Assert.assertEquals("1", exampleServiceMock.aTest());
Assert.assertEquals("2", exampleServiceMock.aTest());
Assert.assertEquals("3", exampleServiceMock.aTest());
Assert.assertEquals("4", exampleServiceMock.aTest());
// 第三次或更多调用都会抛出异常
exampleServiceMock.aTest();
}
ExampleServiceImplTest
import com.jd.work.example.service.ExampleService;
import com.jd.work.example.utils.RedisCache;
import lombok.extern.slf4j.Slf4j;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.runners.MockitoJUnitRunner;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
@Slf4j
@RunWith(MockitoJUnitRunner.class)
//@RunWith(PowerMockRunner.class)
@PrepareForTest()
@PowerMockIgnore("javax.management.*")
public class ExampleServiceImplTest {
/**
* 待测试的具体实现类
*/
@InjectMocks
private ExampleServiceImpl exampleService;
@Mock
private RedisCache redisCache;
/**
* 调用了自身接口的其他方法
*/
@Mock
private ExampleService exampleServiceMock;
@Before
public void setUp() {
// mock注解初始化,不加会报错
MockitoAnnotations.initMocks(this);
}
@Test
public void example() {
PowerMockito.when(exampleServiceMock.bTest()).thenReturn("ok-b");
String s = exampleService.aTest();
Assert.assertEquals("ok-b", s);
}
@Test(expected = RuntimeException.class)
public void continuousCallTest() {
// 模拟连续调用返回指望值,若是分开,则只有最后一个有效
PowerMockito.when(exampleServiceMock.aTest()).thenReturn("1");
PowerMockito.when(exampleServiceMock.aTest()).thenReturn("2");
PowerMockito.when(exampleServiceMock.aTest()).thenReturn("3");
PowerMockito.when(exampleServiceMock.aTest()).thenReturn("4");
PowerMockito.when(exampleServiceMock.aTest()).thenReturn("1").thenReturn("2").thenThrow(new RuntimeException());
Assert.assertEquals("1", exampleServiceMock.aTest());
Assert.assertEquals("2", exampleServiceMock.aTest());
Assert.assertEquals("3", exampleServiceMock.aTest());
Assert.assertEquals("4", exampleServiceMock.aTest());
// 第三次或更多调用都会抛出异常
exampleServiceMock.aTest();
}
@Mock
private List list;
@Test
public void test() {
list.add("test");
verify(list).add("test");
verify(list, atLeastOnce()).add("test");
verify(list, atLeast(1)).add("test");
verify(list, atMost(2)).add("test");
verify(list, never()).add("test111");
assertThat(0, equalTo(list.size()));
}
@Test
public void test3() {
list.add("test");
verify(list).add("test");
// open will fail
// list.clear();
// 代表上一次verify之后再无与list的交互
verifyNoMoreInteractions(list);
}
@Test
public void test4() {
list.add("test");
// 自始至终都与list无任何交互
verifyZeroInteractions(list);
}
}