当前位置:网站首页>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]获取数据
中文文档:
边栏推荐
- new Date converts strings into date formats Compatible with IE, how ie8 converts strings into date formats through new Date, how to replace strings in js, and explain the replace() method in detail
- 复制带随机指针的链表
- 融云「音视频架构实践」技术专场【内含完整PPT】
- How to read the resources files in the directory path?
- 全网没有之一的JMeter 接口测试流程详解
- JVM内存和垃圾回收-07.堆
- 2 Gigabit Optical + 6 Gigabit Electric Rail Type Managed Industrial Ethernet Switch Supports X-Ring Redundant Ring One-key Ring Switch
- C语言--环形缓存区
- TOML configuration file format, YAML's top contender
- [Playwright Test Tutorial] 5 minutes to get started
猜你喜欢
Homemade bluetooth mobile app to control stm8/stm32/C51 onboard LED
Sfdp 超级表单开发平台 V6.0.5 正式发布
C语言--环形缓存区
基地址:环境变量
In a more general sense, calculating the displacement distance and assumptions
Polygon zkEVM network node
出海季,互联网出海锦囊之本地化
2022年最新海南建筑八大员(材料员)模拟考试试题及答案
[Study Notes Dish Dog Learning C] Dynamic Memory Management
跨境电商看不到另一面:商家刷单、平台封号、黑灰产牟利
随机推荐
LeetCode每日一题(2285. Maximum Total Importance of Roads)
2千兆光+6千兆电导轨式网管型工业级以太网交换机支持X-Ring冗余环网一键环网交换机
sqoop ETL工具
There are too many systems, how to realize multi-account interworking?
函数,递归以及dom简单操作
单片机C语言->的用法,和意思
Why use Selenium for automated testing
DIY电工维修如何拆卸和安装开关面板插座
TOML配置文件格式,YAML最有力的竞争者
董明珠直播时冷脸离场,员工频犯低级错误,自家产品没人能弄明白
activiti流程执行过程中,数据库表的使用关系
2022.8.3-----leetcode.899
[Playwright Test Tutorial] 5 minutes to get started
查看mysql死锁语法
Taurus.MVC WebAPI 入门开发教程1:框架下载环境配置与运行(含系列目录)。
第08章 索引的创建与设计原则【2.索引及调优篇】【MySQL高级】
Simple record of Flink principle flow chart
STM8S-----option byte
【观察】超聚变:首提“算网九阶”评估模型,共建开放繁荣的算力网络
The general SQL injection flow (sample attached)