单元测试的重要性,怎么说呢,按照流程规范来讲,每次上线前应该把单元测试都跑一遍,确认通过率是100%才可以。否则我们对现有代码做过修改后,仅依靠测试同学回归验证的话,很容易有场景遗漏,或者隐含未被发现的问题,而且修改公共部分的时候,可能测试的回归量也是很大的。但是,现实情况一般都是,业务代码都写不过来,哪有时间写单测,更别提有质量的单测。
我们目前项目单测的要求是,行覆盖率60%以上,通过率100%。很多时候为了这个指标都是过后才补单测,但其实,这样意义不大。应该在开发业务代码的时候完成单元测试,并用单测来验证代码业务逻辑的正确性。单元测试和代码注释,应该时刻和代码保持一致。
@MockBean: 类的所有方法都需要mock时,使用该注解
@SpyBean: 类的部分方法需要mock时,使用该注解
package com.yst.b2b.dms.controller.dealer.xls;
import com.alibaba.fastjson.JSON;
import com.yst.b2b.dms.TestApplication;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.WebApplicationContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* MockTest
*
* @author xyang010
* @date 2020/8/23
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestApplication.class, webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@Transactional
public class MockTest {
@Autowired
private WebApplicationContext webApplicationContext;
protected MockMvc mockMvc;
@Mock
protected HttpServletResponse response;
@Mock
protected HttpServletRequest request;
@Before
public void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
@MockBean
private UserService userService;
@SpyBean
private OrderService orderService;
/**
* mock service方法的controller接口单测
* @throws Exception
*/
@Test
public void getUserInfo() throws Exception {
Mockito.doReturn(new UserInfo()).when(userService).getUserInfo(Matchers.any());
MvcResult mvcResult = mockMvc
.perform(MockMvcRequestBuilders
.post("/getUserInfo")
.param("userName", Matchers.any())
.accept(MediaType.APPLICATION_JSON_UTF8)
.contentType(MediaType.APPLICATION_JSON_UTF8)
)
.andDo(MockMvcResultHandlers.print())
.andReturn();
MyResult<UserInfo> result = JSON.parseObject(mvcResult.getResponse().getContentAsString(), new TypeReference<MyResult<UserInfo>>() {});
Assert.assertTrue(result.isSuccess());
}
/**
* 直接测试service的方法
*/
@Test
public void getOrderInfo() {
OrderInfo orderInfo = orderService.getOrderInfo(1L);
Assert.assertNotNull(orderInfo);
}
/**
* 测试service方法, mock该方法内调用的同一service内的其他方法
*/
@Test
public void getOrderInfoMock() {
Mockito.doNothing().when(orderService).checkParam(Matchers.any());
Mockito.doNothing().when(orderService).checkOrderExist(Matchers.any());
orderService.getOrderInfo(1L);
}
/**
* 测试异常场景
*/
@Test(expected = RuntimeException.class)
public void getOrderInfoMock() {
Mockito.doNothing().when(orderService).checkParam(Matchers.any());
Mockito.doNothing().when(orderService).checkOrderExist(Matchers.any());
orderService.getOrderInfo(-1L);
}
}
Use Mockito to mock some methods but not others
mockito中两种部分mock的实现,spy、callRealMethod
No qualifying bean of type [org.springframework.web.context.WebApplicationContext]