最近公司要求补充测试用例,正好借这个机会学习下mockito,记录下加深下记忆。
以下测试都是用的
testng
1. 基本使用
java
public class MyTest {
@Test
public void test() {
final MockTest mockTest = Mockito.mock(MockTest.class);
when(mockTest.get()).thenReturn("b");
assertEquals(mockTest.get(), "b");
}
@Test
public void test2() {
assertNull(mockTest.get());
}
public static class MockTest {
public String get() {
return "a";
}
}
}
2. 注解
使用注解必须在使用前调用 MockitoAnnotations.openMocks(this);
, 该方法最后也会调用 Mockito 中的方法。相关类 MockAnnotationProcessor
SpyAnnotationEngine
等。
mockito 自带注解
1. @Mock-mock 一个类,当调用该类中的方法时,都不会产生实际的调用
java
public class MyTest {
@Mock
private MockTest mockTest;
@BeforeClass
public void before(){
MockitoAnnotations.openMocks(this);
}
@Test
public void test() {
when(mockTest.get()).thenReturn("b");
assertEquals(mockTest.get(), "b");
}
public static class MockTest {
public String get() {
return "a";
}
}
}
2. @Spy - 和 @Mock 类似,但是正好相反,该类的方法就会产生实际的调用
java
public class MyTest1 {
@Spy
private MockTest mockTest;
@BeforeClass
public void before() {
MockitoAnnotations.openMocks(this);
}
@Test
public void test() {
assertEquals(mockTest.get(), "a");
}
@Test
public void test2() {
when(mockTest.get()).thenReturn("b");
assertEquals(mockTest.get(), "b");
}
public static class MockTest {
public String get() {
return "a";
}
}
}
注解版本和 @Mock
类似。
3. @InjectMocks - 产生一个真实的实例,并且会注入 @Mock 和 @Spy 的类。
typescript
public class MyTest2 {
@InjectMocks
private MockTest mockTest;
@Mock
private InjectMockObj injectMockObj;
@Spy
private InjectSpybj injectSpybj;
@BeforeClass
public void before() {
MockitoAnnotations.openMocks(this);
}
@Test
public void test() {
assertNull(mockTest.get());
}
@Test
public void test2() {
when(injectMockObj.get()).thenReturn("a");
assertEquals(mockTest.get(), "a");
}
@Test
public void test3() {
assertEquals(mockTest.getSpy(), "a");
}
public static class MockTest {
private InjectMockObj injectMockObj;
private InjectSpybj injectSpybj;
public String get() {
return injectMockObj.get();
}
public String getSpy() {
return injectSpybj.get();
}
}
public static class InjectMockObj {
public String get() {
return "a";
}
}
public static class InjectSpybj {
public String get() {
return "a";
}
}
}
4. @Captor
配合 verify
捕获参数。
typescript
public class MyTest3 {
@Mock
private MockTest mockTest;
@Captor
private ArgumentCaptor<String> captor;
private AutoCloseable closeable;
@BeforeClass
public void open() {
closeable = MockitoAnnotations.openMocks(this);
}
@AfterClass
public void release() throws Exception {
closeable.close();
}
@Test
public void shouldDoSomethingUseful() {
mockTest.set("b");
verify(mockTest).set(captor.capture());
assertEquals("b", captor.getValue());
}
public static class MockTest {
public String set(String a) {
return "a";
}
}
}
Spring Boot 中的注解
@MockBean @SpyBean
和 @Mock @Spy 类似,只是多了一个步骤,会把生成的类替换掉 ApplicationContext 中的类。
常用方法
when(..).thenReturn(..)
doReturn(..).doReturn().when(..).doStuff()
注意在一个方法上可以打两个桩然后有不同的操作,当调用时也会有不同的操作
csharp
public class MyTest4 {
@Mock
private MockTest mockTest;
@BeforeClass
public void before(){
MockitoAnnotations.openMocks(this);
}
@Test
public void test() {
doReturn("b").doReturn("z").when(mockTest).get();
assertEquals(mockTest.get(), "b");
assertEquals(mockTest.get(), "z");
}
@Test
public void test1() {
assertNull(mockTest.get());
}
public static class MockTest {
public String get() {
return "a";
}
}
}
参数匹配
只有当调用的方法的参数和类型和数量匹配时才能触发打桩点。
ArgumentMatchers.any()
匹配任何参数ArgumentMatchers.anyString()
匹配任务字符串ArgumentMatchers.anyInt()
匹配任何Integer值ArgumentMatchers.eq()
匹配某个值- 等等
总结
在使用了几天的 Mockito 之后,我的感受:
- 可以自定义的控制外部依赖对于测试的影响,当外部请求比较复杂时,可以使用 Mockito 来 mock 数据,而无需真正的去调用外部请求。
- 无需自己创建mock数据,减少工作量。