Mock测试
定义
对于单元测试,对于一些不容易构造获取的对象,或者对于尚未开发的模块,创建一个mock对象模拟对象的行为
何时使用mock测试
1、被依赖的对象构造复杂
class A 依赖 class B
class B 依赖 class C和class D
class C 依赖 ...
class D 依赖 ...
比如我们想对A进行测试,而此时需要构造大量的class B、C、D等依赖对象,他们的构造过程复杂,此时可以利用mock构造虚拟的B、C、D对象对我们需要的A进行相关的测试
2、被依赖的模块尚未开发完成,而被测对象需要依赖模块的返回值进行测试
class AController{
@Autowire
private AService service;
public void find(){
service.findAll();
}
}
此时我们的AService尚未构造成功,但我们需要对Acontroller进行测试,我们可以用mock虚拟构造Aservice并构造返回值
如何使用mock进行测试
有一个controller代码如下
import com.zhongkai.errorbook.service.SourceService;
import com.zhongkai.errorbook.util.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
/**
* @author 17715
* 用来查询以及增加错题来源
*/
@RestController
@RequestMapping("/source")
public class SourceController {
@Autowired
private SourceService sourceService;
@GetMapping("/selectSource")
public Result selectSource(String openid){
return sourceService.selectSource(openid);
}
}
此时需要对这个selectController的selectSource进行相关的测试
假设此时的sourceService还没开发完毕
此时的mock测试类为
import com.zhongkai.errorbook.mapper.SourceMapper;
import com.zhongkai.errorbook.service.SourceService;
import com.zhongkai.errorbook.service.impl.SourceServiceImpl;
import com.zhongkai.errorbook.util.CodeMsg;
import com.zhongkai.errorbook.util.Result;
import org.apache.commons.collections4.Get;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultMatcher;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.result.StatusResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import java.sql.ResultSet;
/**
* @author simba@onlying.cn
* @date 2021/4/28 14:08
*/
@RunWith(SpringRunner.class)
public class SourceControllerTest {
/**
* MockMvc主要进行相关的web controller的测试
*/
private MockMvc mockMvc;
/**
* @Mock表示对SourceController依赖的对象进行注入
*/
@Mock
private SourceService service;
/**
* @InjectMocks表示将@Mock的对象注入进SourceController
*/
@InjectMocks
private SourceController sourceController;
/**
* 进行相关的MockMvc的初始化
*/
@Before
public void init() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(sourceController).build();
}
/**
* 通过Mockmvc进行相关的接口请求
* @throws Exception
*/
@Test
public void selectTest() throws Exception {
String openid = "1235664";
//构造service的虚拟对象,模拟返回值
Mockito.when(service.selectSource(openid)).thenReturn(new Result(
new CodeMsg(111, "测试成功")));
//模拟对controller接口的调用,并进行相关的参数校验
this.mockMvc.perform(MockMvcRequestBuilders.get("/source/selectSource").content(openid)
).andExpect(MockMvcResultMatchers.status().isOk());
}
/**
* 不利用MockMvc进行相关的测试,而是直接调用controller进行相关的测试
*/
@Test
public void selectTest2() {
String openid = "1235664";
Result result = new Result(new CodeMsg(111, "测试成功"));
/**
* 此处也可以用 Mockito.when(service.selectSource(Mockito.anyString())).thenReturn(result);
* Mockito可以生成任意的字符串、数字、或者复制对象(用any(Class class))生成
*/
Mockito.when(service.selectSource(openid)).thenReturn(result);
Result result1 = sourceController.selectSource(openid);
Assert.assertEquals(result1, result);
}
}
展示了两种测试controller的方法,对于接口的测试建议还是用第一种进行相关测试
Mockito.when与Mockito.doAnswer的讲解
Mockito.when
Mockito.when(service.selectSource(openid)).thenReturn(new Result(
new CodeMsg(111, "测试成功")));
when与thenReturn进行搭配,表示当执行某个方法的时候返回某个返回值,这个返回值在thenReturn中定义,常用于知道返回值的时候,且此时的参数信息不需要额外处理
Mockito.doAnswer
Mockito.doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
NirvanaWizardProductDO wizardProductDO = invocationOnMock.getArgument(0);
wizardProductDO.setId(1);
return null;
}
}).when(service).updateStatus(wizardProductDO);
doAnswer表示当service执行updateStatus时返回answer方法返回的值,常用来处理参数信息需要额外处理的时候。