1、什么是Mock?
mock是在测试过程中,对于一些不容易构造/获取的对象,创建一个mock对象来模拟对象的行为。比如说你需要调用B服务,可是B服务还没有开发完成,那么你就可以将调用B服务的那部分给Mock掉,并编写你想要的返回结,SpringBoot默认的Mock框架是Mockito,和junit一样,只需要依赖spring-boot-starter-test就可以了。
2、测试过程中常用注解
@RunWith 指定运行环境,例:
@RunWith(SpringRunner.class) Junit运行Spring的测试环境
@RunWith(MockitoJUnitRunner.class) Junit运行Mockito的运行环境,不会加载springboot上下文
@SpringBootTest 加载springboot上下文配置
@WebMvcTest(xxxController.class) 用于测试单个Controller,提供了自配置的MocMvc,可以不启动整个应用就可以以http请求的方 式测试Controller,不过这个注解不会去扫描@Service,@Mapper等注解,当调用这些服务时最好提前打桩,不然会报Error create bean这类异常
@Mock 用于模拟一个服务,例如测试的时候需用调用B服务,但是B服务没写 好,这是可以先Mock一个B服务
@InjectMocks 标注服务的实现类,创建一个实例,其余用@Mock注解创建的mock将被注入到用该实例中
@Before 每个测试方法执行前,执行一次
@After 每个测试方法执行完,执行一次
@Test 标注测试方法
3、测试Service的简单样例,(注:目前项目中单元测试主要测试的是逻辑,第三方api及dao层都会屏蔽掉,所以不用加载整个上下文,建议用这种方式测试)
@RunWith(MockitoJUnitRunner.class)
public classTest{
@Mock
private DataApi dataApi;
@InjectMocks
private DataServiceImpl dataService;
/*
* 准备数据
*/
@Before
public void baseInfo(){
Entity entity=new Entity();
entity.setEndTime(1652544000);
//打桩,当DataService去调用dataApi的selectByPrimaryKey时,会返回模拟的entity数据,anyLong()指任意Long型参数
doReturn(entity).when(dataApi).selectByPrimaryKey(anyLong());
}
@Test
public void testGetData(){
Stirng isOk=dataService.getData(123);
Assert.state("Ok".equals(isOk))//断言,返回预期结果,测试通过
// mock本类中的其他方法
DataServiceImpl dataService1 = Mockito.spy(dataService);
doReturn(false).when(dataService1).getData2(anyList(), any());
// 若需要多次调用一个方法,返回不同的结果,可以按顺序进行return;
when(dataService1.getData2(anyList(), any())).thenReturn("OK").thenReturn(null);
}
// 对测试类中私有变量赋值
// private int maxActive;
@Test
public void dataSourceTest(){
try {
Field apiField = FourthDaoConfiguration.class.getDeclaredField("maxActive");
FieldSetter.setField(fourthDaoConfiguration, apiField, 3);
DruidDataSource result =fourthDaoConfiguration.dataSource();
Assert.assertNotNull(result);
}catch (Exception e){
}
}
// 对测试方法中返回的公用类做mock
@Test
public void updateSystemBalanceTest(){
try {
Long userId =1L;
Integer amount =10;
String actionCause ="aa";
String swiftNumber ="aa";
RLock fairLock =mock(RedissonLock.class);
doReturn(true).when(fairLock).tryLock(50, 60, TimeUnit.SECONDS);
doNothing().when(fairLock).unlock();
doReturn(fairLock).when(redissonClient).getLock(anyString());
int result =partnerAccountActionManager.updateSystemBalance(userId, amount, actionCause, swiftNumber);
Assert.assertTrue(result >0);
}catch (Exception e){
e.printStackTrace();
}
}
}
4、测试Controller简单样例,模仿http发请求,载入springboot的上下文
@RunWith(SpringRunner.class)
@SpringBootTest
public class MockMvcTest{
// 注入web环境的ApplicationContext容器
@Autowired
private WebApplicationContext context;
/**
* 模拟mvc测试对象
*/
private MockMvc mockMvc;
@Before
public void before() throws Exception{
//获取mockmvc对象实例
mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
}
/*
mockMvc.perform 用于发送请求
MockMvcRequestBuilders用于指定请求方式,参数,媒体类型
*/
@Test
public void getInfo() throws Exception{
mockMvc.perform(
MockMvcRequestBuilders.get("/xxx/getInfo")//请求方式,指定URL
.param("xxxx","1489")//请求参数
.param("xxxx","232")
.param("xxxx","0")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)//媒体类型
)
.andExpect(MockMvcResultMatchers.jsonPath("$.code").value(0))//校验响应结果
.andReturn();//返回结果
}
}