为什么会有这篇blog呢,起因上周末看了一个朋友的代码。
结果随便打开他们的测试用例,看一下,这是嘛?
周末补了一下这块的空缺,学无止尽嘛:大致看了一下主体还是很简单的,
官网地址:https://site.mockito.org/
GitHub地址:https://github.com/hehonghui/mockito-doc-zh#0
文档地址:https://javadoc.io/static/org.mockito/mockito-core/3.3.3/org/mockito/Mockito.html
目录
springboot快速搭建一个web项目,用作编写测试用例代码
springboot快速搭建一个web项目,用作编写测试用例代码
pom.xml(基于boot2.x,已经内置junit5跟mock了)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
花几分钟写一个添加用户的功能,DB操作就直接写伪sql了,为啥?因为我懒...
controller
package com.mock.demo.controller;
import com.mock.demo.entry.User;
import com.mock.demo.service.SmsService;
import com.mock.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
import static com.mock.demo.service.impl.UserServiceImpl.userMap;
/**
* @author 954L
* @create 2020/3/24 20:44
*/
@RestController
public class UserController {
@Autowired
private UserService userService;
@Autowired
private SmsService smsService;
@PostMapping("user")
public Map<String, Object> addAndSendSms(@RequestBody User user,
@RequestParam(value = "sendSmsType", defaultValue = "0")
Integer sendSmsType) {
Map<String, Object> result = new HashMap<>();
String name = user.getName();
// 发送注册短信
boolean status = sendSmsType.equals(1) ? smsService.sendSms() : true;
// 查重 & 添加
if (status) status = userMap.get(name) != null ?
false : userService.add(user);
result.put("status", status);
return result;
}
@DeleteMapping("user/{name}")
public Map<String, Object> del(@PathVariable("name") String name){
Map<String, Object> result = new HashMap<>();
// 先添加,再删除
userService.add(User.builder().name(name).build());
boolean status = userService.del(name) ;
result.put("status", status);
return result;
}
}
service
package com.mock.demo.service;
import com.mock.demo.entry.User;
/**
* @author 954L
* @create 2020/3/24 20:47
*/
public interface UserService {
boolean add(User user);
boolean del(String name);
}
package com.mock.demo.service;
/**
* @author 954L
* @create 2020/3/24 20:39
*/
public interface SmsService {
boolean sendSms();
}
impl
package com.mock.demo.service.impl;
import com.mock.demo.entry.User;
import com.mock.demo.service.UserService;
import org.springframework.stereotype.Service;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author 954L
* @create 2020/3/24 20:47
*/
@Service
public class UserServiceImpl implements UserService {
public static Map<String, User> userMap = new ConcurrentHashMap();
@Override
public boolean add(User user) {
// 添加用户
userMap.put(user.getName(), user);
return userMap.containsKey(user.getName());
}
@Override
public boolean del(String name) {
userMap.remove(name);
return !userMap.containsKey(name);
}
}
package com.mock.demo.service.impl;
import com.mock.demo.service.SmsService;
import org.springframework.stereotype.Service;
/**
* @author 954L
* @create 2020/3/24 20:39
*/
@Service
public class SmsServiceImpl implements SmsService {
/**
* 提供给mockito测试模拟对象,返回true
* @return
*/
public boolean sendSms(){
// 无短信功能
return false;
}
}
entity(代码包名写错了,将就下)
package com.mock.demo.entry;
import lombok.Builder;
import lombok.Data;
import lombok.experimental.Tolerate;
/**
* @author 954L
* @create 2020/3/24 20:46
*/
@Data
@Builder
public class User {
private String name;
private Integer age;
@Tolerate
public User(){}
}
测试用例 - mockmvc
mockmvc
模拟web程序发送一个请求
方法 说明 mockMvc.perform 执行一个请求 MockMvcRequestBuilders.get("XXX") 构造一个请求 ResultActions.param 添加请求传值 ResultActions.accept()) 执行一个请求 如MediaType.TEXT_HTML_VALUE ResultActions.andExpect 添加执行完成后的断言。 等同于 Assert.assertEquals
ResultActions.andDo 添加一个结果处理器,表示要对结果做点什么事情,比如此处使用MockMvcResultHandlers.print()输出整个响应结果信息 ResultActions.andReturn 表示执行完成后返回相应的结果。
controllerMockMvcTest
package com.mock.demo.controller;
import com.mock.demo.MockApplication;
import org.json.JSONObject;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
/**
* @author 954L
* @create 2020/3/24 20:03
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MockApplication.class)
@ExtendWith(SpringExtension.class)
@AutoConfigureMockMvc
class UserControllerMockMvcTest {
@Autowired
private MockMvc mockMvc;
@Test
void add() throws Exception {
JSONObject paramJson = new JSONObject();
paramJson.put("name", "Tony");
paramJson.put("age", "18");
mockMvc.perform(MockMvcRequestBuilders.post("/user")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(paramJson.toString())
.accept(MediaType.ALL))
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print());
}
@Test
void del() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.delete("/user/Tony")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.accept(MediaType.ALL))
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print());
}
}
测试用例 - Mockito
mockito
模拟外部依赖,将模拟产生的外部依赖数据与测试代码一起执行
方法 说明 Mockito.mock(classToMock) 模拟对象 Mockito.verify(mock) 验证行为是否发生 Mockito.when(methodCall).thenReturn(value1).thenReturn(value2) 触发时第一次返回value1,第n次都返回value2 Mockito.doThrow(toBeThrown).when(mock).[method] 模拟抛出异常。 Mockito.mock(classToMock,defaultAnswer) 使用默认Answer模拟对象 Mockito.when(methodCall).thenReturn(value) 参数匹配 Mockito.doReturn(toBeReturned).when(mock).[method] 参数匹配(直接执行不判断)
Mockito.when(methodCall).thenAnswer(answer)) 预期回调接口生成期望值 Mockito.doAnswer(answer).when(methodCall).[method] 预期回调接口生成期望值(直接执行不判断) Mockito.spy(Object) 用spy监控真实对象,设置真实对象行为 Mockito.doNothing().when(mock).[method] 不做任何返回 Mockito.doCallRealMethod().when(mock).[method] //等价于Mockito.when(mock.[method]).thenCallRealMethod();
调用真实的方法 reset(mock) 重置mock
controllerMockItoTest
package com.mock.demo.controller;
import com.mock.demo.MockApplication;
import com.mock.demo.entry.User;
import com.mock.demo.service.SmsService;
import com.mock.demo.service.UserService;
import org.junit.Assert;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.junit4.SpringRunner;
import static com.mock.demo.service.impl.UserServiceImpl.userMap;
/**
* @author 954L
* @create 2020/3/24 20:03
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MockApplication.class)
@ExtendWith(SpringExtension.class)
class UserControllerMockItoTest {
@Autowired
private UserService userService;
@Test
void add() {
// 测试添加用户service层,因为依赖短信功能,故这里模拟短信service功能
SmsService smsService = Mockito.mock(SmsService.class);
// 当执行smsService.sendSms(),模拟返回true
Mockito.when(smsService.sendSms()).thenReturn(true);
User user = User.builder().name("testName").age(20).build();
String name = user.getName();
// 发送注册短信
boolean status = smsService.sendSms();
// 查重 & 添加
if (status) status = userMap.get(name) != null ?
false : userService.add(user);
Assert.assertTrue(status);
}
}
对你有帮助的话,右上角给个赞呗~