爲什麼會有這篇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);
}
}
對你有幫助的話,右上角給個讚唄~