当前位置:网站首页>Mockito unit testing
Mockito unit testing
2022-08-04 03:06:00 【The breeze blows, the water waves are unhappy】
Mockito
mockitoA real object can be simulated,Such as simulating objects that need to connect to the database or need to startspring容器的对象,It doesn't actually connect to the database,So the test time is faster.The methods invoked by the simulated object are all by defaultnull、0、false.
使用方式:
1.在测试类上加上@RunWith(MockitoJUnitRunner.class)注解,如果是springboot应用用@ExtendWith(MockitoExtension.class)注解.
2.Mock the object to be tested,有多种方式
- 使用mock方法,如ArrayList list = mock(ArrayList.class);
- 对象上加@Mock注解,并使用MockitoAnnotations.openMocks(this);注册,This method needs to be called before running the test function,一般放在@Before中
- @MockBean
验证verify
@DisplayName("MockitoDemo测试类")
@ExtendWith(MockitoExtension.class)
public class MockitoDemo {
ArrayList list;
@Test
public void mockList() {
list = mock(ArrayList.class); //mock该对象
list.get(0); //At this point any method returns a value of null
verify(list).get(0); //Verify that the object method has been executed.performed here,成功
}
}verify()The way is to verify thatmockWhether the object has executed some methods,If the previous code has not been executed,那会报错,并在控制台上输出 Wanted but not invoked错误.
Same thing with assertions.
打桩Stub
让mockObject methods return some specific value,由自己diy,通过when和then设置.
@Test
public void mockList() {
list = mock(ArrayList.class);
//当get(0)时返回hello
when(list.get(0)).thenReturn("hello");
//get(1)method throws an exception
when(list.get(1)).thenThrow(new RuntimeException("get any"));
System.out.println(list.get(0)); //hello
System.out.println(list.get(1)); //java.lang.RuntimeException: get any
}默认情况下,The return value of a function and function parameter combination without stubbing doesn't make sense,都是返回null类似的值
通过mock(Foo.class, new YourOwnAnswer()); The default can be changed,A program without stubbing decides the return value by itself
Pile driving can be overridden(The last is the final result),但是最好不要
另一种方式:
doReturn(1).when(list).get(0);连续打桩
list = mock(ArrayList.class);
when(list.get(0)).thenReturn(1).thenReturn(2);
//等同于 when(list.get(0)).thenReturn(1,2);
System.out.println(list.get(0)); //1
System.out.println(list.get(0)); //2
System.out.println(list.get(0)); //The follow-up is still2注意:If multiple piling actions are not in one statement,那么就是覆盖
The callback method is piling
list = mock(ArrayList.class);
when(list.get(0)).thenAnswer(new Answer<String>() {
@Override
public String answer(InvocationOnMock invocation) throws Throwable {
Object[] arguments = invocation.getArguments();
Method method = invocation.getMethod();
//invocation.callRealMethod();
Object mock = invocation.getMock();
return "diy 调用方法";
}
});
list.get(0);//diy 调用方法- 通过thenAnswer方法,Parameters are implemented by themselvesAnswer类,这种方式和ProxyDynamic proxies are used in a similar way
另外还有:doNothing()、doCallRealMethod()
参数匹配器matchers
@ExtendWith(MockitoExtension.class)
public class MockitoDemo {
ArrayList list;
@Test
public void mockList() {
list = mock(ArrayList.class);
//可以使用内置的any()、anyInt()etc. matcher,代表所有值、所有整数
when(list.get(anyInt())).thenReturn("get method");
//Custom parameter matchers can be used
when(list.contains(argThat(new MyMatcher()))).thenReturn(true);
System.out.println(list.get(999)); //get method
System.out.println(list.contains(998)); //true
System.out.println(list.contains(999)); //false
//验证是否调用过get函数.这里的anyInt()就是一个参数匹配器.
verify(list).get(anyInt());
}
}
//Custom parameter matcher class
class MyMatcher implements ArgumentMatcher<Integer> {
@Override
public boolean matches(Integer v) {
//Represents all even numbers
return v % 2 == 0;
}
}注意:if you use parameter matchers, Then all parameters must use matchers.
verify(mock).someMethod(anyInt(), anyString(), eq("third argument"));
// 上述代码是正确的,因为eq()也是一个参数匹配器Verification continued
验证次数
verify()The method actually needs to specify how many times the corresponding method is executed,默认是1次.
list = mock(ArrayList.class);
list.add(1);
list.add(2);list.add(2);
list.add(3);list.add(3);list.add(3);
verify(list,times(1)).add(1); //等于verify(list).add(1)
verify(list,times(2)).add(2); //表示add(2)Need to execute just fine2次
verify(list,times(3)).add(3);
verify(list,atLeast(2)).add(3); //最少执行2次
verify(list,atMost(2)).add(1); //最多执行2次
verify(list,never()).add(999); //violated the execution验证执行顺序
用于限制mock对象的执行顺序
list = mock(ArrayList.class);
list.get(0);
list.get(1);
//1.为该mock对象创建inorder验证器
InOrder inOrder = inOrder(list);
//2.Perform validations in the order you want,If the sequence is consistent, the verification is successful
inOrder.verify(list).get(0);
inOrder.verify(list).get(1);
//Verification in order failure ,验证失败
//inOrder.verify(list).get(1);
//inOrder.verify(list).get(0);The above example is the execution order of a single object method,也可以限制多个mock对象:
list1 = mock(ArrayList.class);
list2 = mock(ArrayList.class);
list1.get(0);
list2.get(1);
//1.为这两个mock对象创建inorder验证器
InOrder inOrder = inOrder(list1, list2);
//2.验证通过
inOrder.verify(list1).get(0);
inOrder.verify(list2).get(1);Authentication with timeout
Authentication timeout,Verification fails immediately if it takes too long
verify(mock, timeout(500).times(1)).method();spy监控
用于创建spy间谍,to monitor real objects,使用spyThe real method is called when the object is called,But you can also givespyObject method stubs.In fact, it is the real object andmockThe intermediate form of the object.
LinkedList<String> linkedList = new LinkedList<>();
LinkedList<String> spy = spy(linkedList); //创建spy对象
doReturn(100).when(spy).size(); //Pile certain methods
spy.add("one");
spy.add("two");
System.out.println(spy); //[one, two]
System.out.println(spy.size()); //100
verify(spy).add("one"); //验证通过- Note that the real object is still unchanged,变的只是spy对象.
- 和@Mock类似,还可以用@Spy注解.
ArgumentCaptor
Most of the previous verification is to verify the process of method invocation,If you want to verify the parameters used when the method is called, you need to use itArgumentCaptor.
ArrayList<String> list = mock(ArrayList.class);
//mockThe object is called twiceadd方法,注意参数
list.add("zhangsan");
list.add("lisi");
//创建ArgumentCaptor对象,StringGeneric is the parameter type of the method that needs to be captured
ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
//调用verify并且捕捉list.add调用的所有参数.Care needs to be taken to prevent validation failures
verify(list,atLeast(0)).add(argumentCaptor.capture());
//断言,argumentCaptor.getValue()Returns the parameters of the last method call
Assertions.assertEquals("lisi", argumentCaptor.getValue());
//argumentCaptor.getAllValues()Returns all parameter values
Assertions.assertArrayEquals(new Object[]{"zhangsan","lisi"},
argumentCaptor.getAllValues().toArray());Use the custom parameter matcher aboveArgument MatcherValidation of parameters can also be achieved,使用ArgumentCaptorIt is more suitable in the following cases :
- Custom parameter matchers that cannot be reused
- You only need to assert the parameter value
It is better to use a custom parameter matcher when piling.
行为驱动开发
采用given->when->thatorder to write unit tests
自动实例化
@InjectMocks注解和@Mock配合使用,For mock objects with dependencies
@Data
public class UserInfo {
private String name;
private String password;
public UserInfo(String name, String password) {
this.name = name;
this.password = password;
}
}@Service
public class UserInfoService {
@Autowired
private UserInfoDao userInfoDao;
public void printInfo() {
UserInfo userInfo = userInfoDao.select();
System.out.println(userInfo);
}
}
public interface UserInfoDao {
UserInfo select();
}如果我要测试这个service,并且不想和数据库有交互,那么可以创建一个UserInfoDao mock对象.被测试类标注为@InjectMocks时,会自动实例化,并且把@Mock或者@Spy标注过的依赖注入进去.
@ExtendWith(MockitoExtension.class)
public class UserInfoServiceTest {
@InjectMocks
private UserInfoService userInfoService;
@Mock
private UserInfoDao userInfoDao;
@Test
public void testPrint() {
UserInfo userInfo = new UserInfo("admin", "123");
when(userInfoDao.select()).thenReturn(userInfo);
userInfoService.printInfo();
}
}springboot测试
1.controller
mockito提供了MockMvc类,用于模拟web环境,发送请求到controller.
MockMvcBuilders.* 初始化web环境,有两种初始化方式
- MockMvcBuilders.standaloneSetup(hrjtCcsDealController).build() 针对单个controllerBuild the environment
- MockMvcBuilders.webAppContextSetup(webAppContext).build() 针对整个webenvironment is constructed
- MockMvcRequestBuilders.* 构造请求:有get、post……
- MockMvcResultMatchers.*:搭配ResultActions接口的andExpect()method to match the desired result.MockMvcResultMatchers.status()The method returns the usual result judgment
- MockMvcResultHandlers.*:搭配ResultActions接口的andDo()方法对结果进行处理.MockMvcResultHandlers.print()The method returns the usual result judgment
注意:Currently a single class container is not recognizedswaggerValidation annotations for parameters.
@DisplayName("StudentController的测试")
@LunaFrameworkTest(classes = {BizTestConfig.class})
public class StudentControllerTest {
public MockMvc mockMvc;
@InjectMocks
public StudentController studentController;
@Mock
public StudentService studentService;
@Before
public void before() {
MockitoAnnotations.openMocks(this);
//构建MockMvc
mockMvc = MockMvcBuilders.standaloneSetup(studentController).build();
}
@Test
public void t1() throws Exception {
StudentPO studentPO = getStudent();
//任何情况都返回0
Mockito.when(studentService.create(any())).thenReturn(0);
//Overwrite the previous statement,如果pojo校验正确,返回1
Mockito.when(studentService.create(argThat(new StudentVerfiy()))).thenReturn(1);
//发送create请求
mockMvc.perform(MockMvcRequestBuilders.post("/student/create")
//设置request请求的内容
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(asJson(studentPO))
.accept(MediaType.APPLICATION_JSON_UTF8)
)
//校验response是否为200,Insertion is successful200
.andExpect(status().isOk())
//.andExpect(content().json("xxx"))
//打印
.andDo(print());
}
public StudentPO getStudent() {
StudentPO studentPO = new StudentPO();
studentPO.setUrid(UuidUtils.generateUuid());
studentPO.setAge(20);
studentPO.setName("马大哈");
studentPO.setClassid("2");
studentPO.setSex("男");
studentPO.setTenantid(20L);
studentPO.setHeight(169.2f);
return studentPO;
}
public String asJson(Object o) {
ObjectMapper objectMapper = new ObjectMapper();
String s;
try {
s = objectMapper.writeValueAsString(o);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
return s;
}
}
//Custom validator
class StudentVerfiy implements ArgumentMatcher<StudentPO> {
@Override
public boolean matches(StudentPO argument) {
//写校验逻辑
if (argument.getAge() > 150 || argument.getAge() < 0)
return false;
if (!argument.getSex().equals("男") && !argument.getSex().equals("女"))
return false;
return true;
}
}- .perform() : 执行一个MockMvcRequestBuilders的请求;MockMvcRequestBuilders有.get()、.post()、.put()、.delete()等请求.
- .andDo() : 添加一个MockMvcResultHandlers结果处理器,可以用于打印结果输出(MockMvcResultHandlers.print()).
- .andExpect : 添加MockMvcResultMatchers验证规则,验证执行结果是否正确.
2.service层
Use lazy loading of classes,Only for current useservice进行bean注入.当前service中涉及到的DaoManager和Client都要mock.
@DisplayName("StudentService的测试")
@LunaFrameworkTest(classes = {BizTestConfig.class, AbstractDaoTestConfig.class})
public class StudentServiceTest {
@InjectMocks //The interface needs to be initialized manually
private StudentService studentService = new StudentServiceImpl();
@Mock
private StudentMapper studentMapper;
@Test
public void t1() {
Mockito.when(studentMapper.insert(any())).thenReturn(0);
Mockito.when(studentMapper.insert(argThat(new StudentVerfiy()))).thenReturn(1);
int res = studentService.create(getStudent());
Assertions.assertEquals(1, res);
}
@Before
public void start() {
MockitoAnnotations.openMocks(this);
}
}补充:@[email protected]获取数据
中文文档:
边栏推荐
- [Original] Start the XPS/OXPS reader that comes with Windows 10
- There are too many systems, how to realize multi-account interworking?
- [QNX Hypervisor 2.2用户手册]10.3 vdev gic
- new Date将字符串转化成日期格式 兼容IE,ie8如何通过new Date将字符串转化成日期格式,js中如何进行字符串替换, replace() 方法详解
- 查看mysql死锁语法
- 多线程间的通信方式你知道几种?
- STM8S-----option byte
- 【医保科普】维护医保基金安全,我们可以这样做
- SQL注入中 #、 --+、 --%20、 %23是什么意思?
- MCU C language -> usage, and meaning
猜你喜欢

自定义通用分页标签02

Development of Taurus. MVC WebAPI introductory tutorial 1: download environment configuration and operation framework (including series directory).

Zabbix设置邮件告警+企业微信告警

6-port full Gigabit Layer 2 network managed industrial Ethernet switch Gigabit 2 optical 4 electrical fiber self-healing ERPS ring network switch

pytorch applied to MNIST handwritten font recognition

跨境电商看不到另一面:商家刷单、平台封号、黑灰产牟利

融云「音视频架构实践」技术专场【内含完整PPT】

三分建设,七分管理!产品、系统、组织三管齐下节能降耗

基本表单验证流程

JVM内存和垃圾回收-07.堆
随机推荐
倒计时2天,“文化数字化战略新型基础设施暨文化艺术链生态建设发布会”启幕在即
第08章 索引的创建与设计原则【2.索引及调优篇】【MySQL高级】
Gigabit 2 X light 8 electricity management industrial Ethernet switches WEB management - a key Ring Ring net switch
Homemade bluetooth mobile app to control stm8/stm32/C51 onboard LED
【指针内功修炼】深度剖析指针笔试题(三)
kingbaseES V8R2/R3 表在指定表空间,为何显示为默认表空间?
一文看懂推荐系统:召回05:矩阵补充、最近邻查找,工业界基本不用了,但是有助于理解双塔模型
创新互融|华秋赋能助力OpenHarmony生态硬件开发落地
为什么用Selenium做自动化测试
从图文展示到以云为核,第五代验证码独有的策略情报能力
FPGA解析B码----连载3
Mockito单元测试
网络工程师入门必懂华为认证体系,附系统学习路线分享
单片机C语言->的用法,和意思
new Date将字符串转化成日期格式 兼容IE,ie8如何通过new Date将字符串转化成日期格式,js中如何进行字符串替换, replace() 方法详解
Deep Learning (3) Classification Theory Part
4路双向HDMI综合业务高清视频光端机8路HDMI高清视频光端机
docker+网桥+redis主从+哨兵模式
TOML configuration file format, YAML's top contender
View mysql deadlock syntax