mockito的最佳实践

本文介绍了Mockito的使用技巧,包括如何mock发送请求给controller、mock依赖、参数匹配、mock void方法、处理不可变final依赖、构造函数注入、Test Spy的运用以及Mockito的基本理论和参考资料。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

9.参考资料

Mockito Tutorial

Mockito 详细说明

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值