引入依賴的包:java
<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>2.23.4</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito2</artifactId> <version>2.0.2</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-core</artifactId> <version>2.0.2</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>2.0.2</version> <scope>test</scope> </dependency>
MockMvc + PowerMock + Mockito 來模擬post get請求,並mock掉service中存在doGet doPost外部系統的restful請求web
@RunWith(PowerMockRunner.class) @PowerMockRunnerDelegate(SpringRunner.class) @prepareForTest({ HttpUtil.class // doGet doPost 使用util類,這裏須要告訴UT }) @PowerMockIgnore("javax.crypto.*") @AutoConfigureMockMvc @SpringBootTest public class DemoSzlTest { @Autowired private WebApplicationContext webApplicationContext; private MockMvc mockMvc; @Before public void setUp() throws Exceptioin { MockitoAnnotations.initMocks(this); // 初始化裝載powerMockito mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); } @Test @DirtiesContext public void testPostDemo() throws Exception { // mock HttpResponse 對象返回 StringEntity se = new StringEntity("xxxxxx", "utf-8"); HttpResponse resp = new BasicHttpResponse(new BasicStatusLine(HttpVersion.Http_1_1, HttpServletResponse.SC_OK, "")); resp.setEntity(se); PowerMockito.mockStatic(HttpUtil.class);
// 這裏的 Mockito.anyString() 要和 實際方法參數保持一致
PowerMockite.when(HttpUtil.doGet(Mockito.anyString(), Mockito.anyMap(), Mockito.any())).thenReturn(resp); // 這裏不 mock方法,直接走真實場景方法
PowerMockito.when(HttpUtil.toJson(Mockito.anyObject())).thenCallRealMethod();
// body contents String jsonBody = "{\"aaaa\":\"1111\"}"; String token = "xxxxx"; MvcResult resultMsg = mockMvc.perform( post("/xxx") .contentType(MediaType.APPLICATION_JSON_VALUE) .accept(MediaType.APPLICATION_JSON_UTF8_VALUE) .header("xxxxx", token) .content(jsonBody) // request body ).andExpect(status().isCeated()) .andReturn(); }
@Test
@DirtiesContext
public void contextLoads() throws Exception {
// 這裏定義的 header 值 必需要和service層使用的值保持一致,不然powerMock mock時會有問題
// 其實也很好理解,既然要mock,那就作到真實一點,一切都保持如出一轍便可。
Header[] header = {
new BasicHeader("Authorization", "aaabbbccc"),
new BasicHeader("Content-Type", "application/json")
};
// 手動建立HttpResponse,來模式http請求的返回值
StringEntity se = new StringEntity("{"
+ "\"memo\":\"這個只是demo式樣\"}", "utf-8");
HttpResponse resp = new BasicHttpResponse(new BasicStatusLine(HttpVersion.HTTP_1_1,
HttpServletResponse.SC_OK, ""));
resp.setEntity(se);
// 和上面說明一致
StringEntity se2 = new StringEntity("{"
+ "\"memo\":\"這個只是demo2式樣\"}", "utf-8");
HttpResponse resp2 = new BasicHttpResponse(new BasicStatusLine(HttpVersion.HTTP_1_1,
HttpServletResponse.SC_OK, ""));
resp2.setEntity(se2);
// 開始mock咱們想要的靜態方法,此處是mock post請求並返回上面咱們mock的值
PowerMockito.mockStatic(HttpUtil.class);
/**
* 本人是爲了達到一個service裏連續調用2次post請求,但2次請求內容不一樣,返回結果也不一樣,進行mock
* Mockito.eq("/aaa") 是mock值
* Mockito.eq("aaabbb") 是mock值
* Mockito.any(header.getClass()) 是mock Header[]值
*/
PowerMockito.when(HttpUtil.doPost(Mockito.eq("/aaa"), Mockito.eq("aaabbb"), Mockito.any(header.getClass()))).thenReturn(resp);
PowerMockito.when(HttpUtil.doPost(Mockito.eq("/bbb"), Mockito.eq("cccddd"), Mockito.any(header.getClass()))).thenReturn(resp2);
String jsonBody = "{\"aaaa\":\"1111\"}";
String token = "xxxxx";
MvcResult resultMsg = mockMvc.perform(
post("/testUTDemo")
.header("Authorization", token)
.content(jsonBody) // request body
).andExpect(status().isCreated()).andReturn();
} }
Controller類:spring
package com.szl.demo.szldemo.controller; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import com.szl.demo.szldemo.common.dto.UserDto; import com.szl.demo.szldemo.service.UserService; import lombok.extern.slf4j.Slf4j; @Slf4j @Controller public class DemoController { @Autowired private UserService userService; @ResponseBody @RequestMapping(value = "/testUTDemo", method = RequestMethod.POST) public UserDto testUTDemo(HttpServletRequest request, HttpServletResponse response) { return userService.testDemoUnitTest(); } }
Service接口:apache
package com.szl.demo.szldemo.service; import com.szl.demo.szldemo.common.dto.UserDto; public interface UserService { UserDto testDemoUnitTest(); }
Service實現類:json
package com.szl.demo.szldemo.service.impl; import org.apache.commons.io.IOUtils; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.message.BasicHeader; import org.springframework.stereotype.Service; import com.szl.demo.szldemo.common.dto.UserDto; import com.szl.demo.szldemo.common.util.HttpUtil; import com.szl.demo.szldemo.service.UserService; import lombok.extern.slf4j.Slf4j; @Slf4j @Service("userService") public class UserServiceImpl implements UserService { public UserDto testDemoUnitTest() { try { Header[] header = { new BasicHeader("Authorization", "aaabbbccc"), new BasicHeader("Content-Type", "application/json") };
// 此處的代碼塊也是mock的重點 HttpResponse resp = HttpUtil.doPost("/aaa", "aaabbb", header); HttpEntity entity = resp.getEntity(); String msg = IOUtils.toString(entity.getContent(), "UTF-8"); log.info("msg: " + msg);
// 同上 HttpResponse resp2 = HttpUtil.doPost("/bbb", "cccddd", header); HttpEntity entity2 = resp2.getEntity(); String msg2 = IOUtils.toString(entity2.getContent(), "UTF-8"); log.info("msg2: " + msg2); } catch (Exception e) { e.printStackTrace(); }
// 這裏隨便賦值並返回,主要不是看這裏的功能 UserDto dto = new UserDto(); dto.setId(1001L); dto.setNickName("test"); dto.setUserId(10000001L); return dto; } }
HttpUtil.java類:api
public class HttpUtil { public static HttpResponse doGet(String url, Map<String, String> params, Header[] headers) { ..... 這裏省略 }
public static JsonObject toJson(HttpResponse httpResponse) {
.....
這裏省略
}
public static HttpResponse doPost(String url, String params, Header[] header) {
// 這裏只是爲了演示,手動建立StringEntity並賦值,手動建立HttpResponse並返回
HttpResponse resp = new BasicHttpResponse(new BasicStatusLine(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, null));
StringEntity se1 = new StringEntity("{"
+ "\"alg\":\"aqas\","
+ "\"id\":\"122011\"}", "utf-8");
resp.setEntity(se1);
return resp;
} }
UserDto類: restful
package com.szl.demo.szldemo.common.dto; import java.io.Serializable; import lombok.Data; @Data public class UserDto implements Serializable { private static final long serialVersionUID = -8858511759866491158L; private Long id; private Long userId; private String nickName; }
好了,讓咋們來試試上面的UT跑出什麼結果,以下圖:app
OK, 大功告成,若有博友須要,供參考,需轉發,請註明引自連接,謝謝。post
另附上額外功能,若是有朋友須要在UT裏按順序執行,須要加註解:ui
@FixMethodOrder(xxx)
這裏的xxx有三種模式:
- 默認(MethodSorters.DEFAULT)
- 按方法名(MethodSorters.NAME_ASCENDING)
- JVM(MethodSorters.JVM)
一開始本人使用JVM模式,雖然能達到預期,但運行不太穩定,本人仍是推薦你們使用NAME_ASCENDING模式
若有朋友參考本人的筆記,有問題能夠留言,轉載請註明原著,謝謝。