1.如何mock发送请求给controller
- GET
@Test
public void testMonitor() throws Exception {
String url = "/monitor/alive";
String jsonStr = mockMvc.perform(get(url)).andExpect(status().isOk()).andDo(print()).andReturn().getResponse().getContentAsString();
JsonNode json = mapper.readTree(jsonStr);
Assert.assertEquals(HttpStatus.SC_OK, json.get("code").intValue());
}
- POST
@Test
public void createStudentCourse() throws Exception {
Course mockCourse = new Course("1", "Smallest Number", "1",Arrays.asList("1", "2", "3", "4"));
// studentService.addCourse to respond back with mockCourse
Mockito.when(studentService.addCourse(Mockito.anyString(),Mockito.any(Course.class))).thenReturn(mockCourse);
// Send course as body to /students/Student1/courses
RequestBuilder requestBuilder = MockMvcRequestBuilders
.post("/students/Student1/courses")
.accept(MediaType.APPLICATION_JSON)
.content(exampleCourseJson)
.contentType(MediaType.APPLICATION_JSON);
MvcResult result = mockMvc.perform(requestBuilder).andReturn();
MockHttpServletResponse response = result.getResponse();
assertEquals(HttpStatus.CREATED.value(), response.getStatus()); assertEquals("http://localhost/students/Student1/courses/1",response.getHeader(HttpHeaders.LOCATION));
}
2.如何mock依赖
- service 依赖dao,将dao依赖注入到service中;(必须满足这个条件哦,这种方式的field无法注入BeanPoolUtil.getBean)
- @Mock 创建CustomerDao的mock实例
- @InjectMocks 创建service时注入@Mock实例
- MockitoAnnotations.initMocks(this);创建上面的实例
public class CustomerServiceTest {
@Mock
private CustomerDao daoMock;
@InjectMocks
private CustomerService service;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
@Test
public void test() {
//assertion here
}
}
3.参数匹配-匹配Enum
Mockito.when(object.doThings(Matchers.any(MyEnum.class), Matchers.anyLong()))
.thenReturn(123L);
4.如何mock void的method
- doAnswer 模拟void方法行为
- doThrow 模拟void方法的异常
@Test
public void updateStatus() {
ImageTask task = new ImageTask().setStatus(ImageTaskStatus.SUCCESS.getStatus()).setMessage("test");
doAnswer((InvocationOnMock invocation) -> {
return null;
}).when(imageTaskDao).updateTaskStatus(any(ImageTask.class));
ImageTask task1 = new ImageTask();
Assert.assertTrue(imageTaskService.updateStatus(task1, ImageTaskStatus.SUCCESS, "test"));
verify(imageTaskDao, times(1)).updateTaskStatus(any(ImageTask.class));
}
5.如何mock 不可变final的依赖field
- InjectMocks会忽略final和static的域;就是这两种域不能通过injectMocks来模拟,需要自己管理依赖;
- 这是by design的设计,参考如下
- https://github.com/mockito/mockito/issues/352
- 但是final的方法和类不受影响
@Test
public void whenMockFinalMethodMockWorks() {
MyList myList = new MyList();
MyList mock = mock(MyList.class);
when(mock.finalMethod()).thenReturn(1);
assertNotEquals(mock.finalMethod(), myList.finalMethod());
}
6.构造函数有参数,如何注入
- 参数中的对象必须都被mock管理,否则不会发生注入inject。
public class ArticleManager {
private ArticleDatabase database;
private ArticleCalculator calculator;
ArticleManager(ArticleObserver observer, boolean flag) {
// observer is not declared in the test above.
// flag is not mockable anyway
}
}
7.Test Spy
- 可以认为是由记录功能的test sub
@Spy
List<string> listSpy = new ArrayList<string>();
@Test
public void testSpyReturnsRealValues() throws Exception {
String s = "dobie";
listSpy.add(new String(s));
verify(listSpy).add(s);
assertEquals(1, listSpy.size()); // 如果list仅仅是@Mock的话,这里的size是0
}
</string></string>
- 场景:调用真实的依赖的方法,同时需要验证或者跟踪依赖的交互行为(sub无法实现)
public class CustomerServiceTestV2 {
@Spy
private CustomerDaoImpl daoSpy;
@InjectMocks
private CustomerService service;
// setup
@Test
public void test() {
// exercise
Customer customer = new Customer();
assertThat(service.addCustomer(customer), is(false));
// verify
verify(daoSpy).save(any(Customer.class));
verify(daoSpy, times(1)).exists(anyString());
verify(daoSpy, never()).delete(any(Customer.class));
}
}
8.一些理论概念,sub/spy/mock
- 过程:setUp - Exercise - Verify - tearDown
How to Mocks And Stubs - Understanding Test Doubles With Mockito
xUnit Patterns