日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring MVC控制器的单元测试:REST API

發布時間:2023/12/3 javascript 52 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring MVC控制器的单元测试:REST API 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Spring MVC提供了一種創建REST API的簡便方法。 但是,為這些API編寫全面而快速的單元測試一直很麻煩。 Spring MVC測試框架的發布使我們可以編寫可讀,全面且快速的單元測試。

這篇博客文章描述了如何使用Spring MVC Test框架編寫REST API的單元測試。 在這篇博客中,我們將為控制器方法編寫單元測試,這些方法為待辦事項提供CRUD功能。

讓我們開始吧。

使用Maven獲取所需的依賴關系

通過將以下依賴項聲明添加到我們的POM文件中,我們可以獲得所需的測試依賴項:

  • Hamcrest 1.3( hamcrest-all )。 在為響應編寫斷言時,我們使用Hamcrest匹配器。
  • Junit 4.11。 我們需要排除hamcrest-core依賴性,因為我們已經添加了hamcrest-all依賴性。
  • Mockito 1.9.5( mockito-core )。 我們使用Mockito作為我們的模擬庫。
  • Spring測試3.2.3發布
  • JsonPath 0.8.1( json-path和json-path-assert )。 在為REST API返回的JSON文檔編寫斷言時,我們使用JsonPath。

相關的依賴項聲明如下所示:

<dependency><groupId>org.hamcrest</groupId><artifactId>hamcrest-all</artifactId><version>1.3</version><scope>test</scope> </dependency> <dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope><exclusions><exclusion><artifactId>hamcrest-core</artifactId><groupId>org.hamcrest</groupId></exclusion></exclusions> </dependency> <dependency><groupId>org.mockito</groupId><artifactId>mockito-core</artifactId><version>1.9.5</version><scope>test</scope> </dependency> <dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>3.2.3.RELEASE</version><scope>test</scope> </dependency> <dependency><groupId>com.jayway.jsonpath</groupId><artifactId>json-path</artifactId><version>0.8.1</version><scope>test</scope> </dependency> <dependency><groupId>com.jayway.jsonpath</groupId><artifactId>json-path-assert</artifactId><version>0.8.1</version><scope>test</scope> </dependency>

讓我們繼續討論一下單元測試的配置。

配置我們的單元測試

我們將在此博客文章中編寫的單元測試使用基于Web應用程序上下文的配置。 這意味著我們通過使用應用程序上下文配置類或XML配置文件來配置Spring MVC基礎結構。

因為本教程的第一部分描述了配置應用程序的應用程序上下文時應遵循的原則,所以本博文中未討論此問題。

但是,我們必須在這里解決一件事。

配置示例應用程序的Web層的應用程序上下文配置類(或文件)不會創建異常解析器bean。 本教程前面部分中使用的SimpleMappingExceptionResolver類將異常類名稱映射到拋出配置的異常時呈現的視圖。

如果我們正在實現“常規” Spring MVC應用程序,那么這是有道理的。 但是,如果要實現REST API,則希望將異常轉換為HTTP狀態代碼。 默認情況下,此行為由ResponseStatusExceptionResolver類提供。

我們的示例應用程序還具有一個自定義異常處理程序類,該類以@ControllerAdvice批注進行批注 。 此類處理驗證錯誤和應用程序特定的異常。 我們將在本博客文章的后面部分詳細討論此類。

讓我們繼續前進,了解如何為REST API編寫單元測試。

編寫REST API的單元測試

在開始為REST API編寫單元測試之前,我們需要了解兩點:

  • 我們需要知道Spring MVC Test框架的核心組件是什么。 這些組件在本教程的第二部分中進行了描述。
  • 我們需要知道如何使用JsonPath表達式編寫JSON文檔的斷言。 我們可以通過閱讀我的博客文章獲得此信息,該文章描述了如何使用JsonPath編寫干凈的斷言 。

接下來,我們將看到運行中的Spring MVC Test框架,并為以下控制器方法編寫單元測試:

  • 第一個控制器方法返回待辦事項列表。
  • 第二種控制器方法返回單個待辦事項的信息。
  • 第三種控制器方法將新的待辦事項條目添加到數據庫,并返回添加的待辦事項條目。

獲取待辦事項

第一個控制器方法返回從數據庫中找到的待辦事項列表。 讓我們先來看一下該方法的實現。

預期行為

通過執行以下步驟來實現將所有待辦事項返回到數據庫的控制器方法:

  • 它處理發送到url'/ api / todo'的GET請求。
  • 它通過調用TodoService接口的findAll()方法獲取Todo對象的列表。 此方法返回存儲在數據庫中的所有待辦事項。 這些待辦事項條目總是以相同的順序返回。
  • 它將接收到的列表轉換為TodoDTO對象的列表。
  • 它返回包含TodoDTO對象的列表。
  • TodoController類的相關部分如下所示:

    import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*;import java.util.ArrayList; import java.util.List;@Controller public class TodoController {private TodoService service;@RequestMapping(value = "/api/todo", method = RequestMethod.GET)@ResponseBodypublic List<TodoDTO> findAll() {List<Todo> models = service.findAll();return createDTOs(models);}private List<TodoDTO> createDTOs(List<Todo> models) {List<TodoDTO> dtos = new ArrayList<>();for (Todo model: models) {dtos.add(createDTO(model));}return dtos;}private TodoDTO createDTO(Todo model) {TodoDTO dto = new TodoDTO();dto.setId(model.getId());dto.setDescription(model.getDescription());dto.setTitle(model.getTitle());return dto;} }

    當返回TodoDTO對象列表時,Spring MVC將此列表轉換為包含對象集合的JSON文檔。 返回的JSON文檔如下所示:

    [{"id":1,"description":"Lorem ipsum","title":"Foo"},{"id":2,"description":"Lorem ipsum","title":"Bar"} ]

    讓我們繼續并編寫一個單元測試,以確保此控制器方法按預期工作。

    測試:找到待辦事項

    通過執行以下步驟,我們可以為此控制器方法編寫單元測試:

  • 創建測試數據,該數據將在調用TodoService接口的findAll()方法時返回。 我們通過使用測試數據構建器類來創建測試數據。
  • 配置我們的模擬對象,使其在調用findAll()方法時返回創建的測試數據。
  • 執行GET請求以獲取網址“ / api / todo”。
  • 驗證是否返回HTTP狀態代碼200。
  • 確認響應的內容類型為“ application / json”,其字符集為“ UTF-8”。
  • 使用JsonPath表達式$獲取待辦事項的集合,并確保返回兩個待辦事項。
  • 通過使用JsonPath表達式$ [0] .id , $ [0] .description和$ [0] .title來獲取第一個todo條目的id , 描述和標題 。 驗證是否返回了正確的值。
  • 通過使用JsonPath表達式$ [1] .id , $ [1] .description和$ [1] .title來獲取第二個待辦事項的ID , 描述和標題。 驗證是否返回了正確的值。
  • 驗證TodoService接口的findAll()方法僅被調用一次。
  • 確保在測試過程中沒有調用模擬對象的其他方法。
  • 我們的單元測試的源代碼如下所示:

    import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc;import java.util.Arrays;import static org.hamcrest.Matchers.*; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {TestContext.class, WebAppContext.class}) @WebAppConfiguration public class TodoControllerTest {private MockMvc mockMvc;@Autowiredprivate TodoService todoServiceMock;//Add WebApplicationContext field here.//The setUp() method is omitted.@Testpublic void findAll_TodosFound_ShouldReturnFoundTodoEntries() throws Exception {Todo first = new TodoBuilder().id(1L).description("Lorem ipsum").title("Foo").build();Todo second = new TodoBuilder().id(2L).description("Lorem ipsum").title("Bar").build();when(todoServiceMock.findAll()).thenReturn(Arrays.asList(first, second));mockMvc.perform(get("/api/todo")).andExpect(status().isOk()).andExpect(content().contentType(TestUtil.APPLICATION_JSON_UTF8)).andExpect(jsonPath("$", hasSize(2))).andExpect(jsonPath("$[0].id", is(1))).andExpect(jsonPath("$[0].description", is("Lorem ipsum"))).andExpect(jsonPath("$[0].title", is("Foo"))).andExpect(jsonPath("$[1].id", is(2))).andExpect(jsonPath("$[1].description", is("Lorem ipsum"))).andExpect(jsonPath("$[1].title", is("Bar")));verify(todoServiceMock, times(1)).findAll();verifyNoMoreInteractions(todoServiceMock);} }

    我們的單元測試使用一個稱為APPLICATION_JSON_UTF8的常量,該常量在TestUtil類中聲明。 該常量的值是MediaType對象,其內容類型為“ application / json”,字符集為“ UTF-8”。

    TestUtil類的相關部分如下所示:

    public class TestUtil {public static final MediaType APPLICATION_JSON_UTF8 = new MediaType(MediaType.APPLICATION_JSON.getType(), MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8") ); }

    獲取待辦事項條目

    我們必須測試的第二個控制器方法返回單個待辦事項的信息。 讓我們找出如何實現此控制器方法。

    預期行為

    通過執行以下步驟來實現返回單個待辦事項信息的控制器方法:

  • 它處理發送到url'/ api / todo / {id}'的GET請求。 {id}是一個路徑變量,其中包含請求的待辦事項條目的ID 。
  • 它通過調用TodoService接口的findById()方法獲取請求的待辦事項條目,并將請求的待辦事項條目的ID作為方法參數傳遞。 此方法返回找到的待辦事項條目。 如果未找到待辦事項條目,則此方法將拋出TodoNotFoundException 。
  • 它將Todo對象轉換為TodoDTO對象。
  • 它返回創建的TodoDTO對象。
  • 我們的控制器方法的源代碼如下所示:

    import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*;@Controller public class TodoController {private TodoService service;@RequestMapping(value = "/api/todo/{id}", method = RequestMethod.GET)@ResponseBodypublic TodoDTO findById(@PathVariable("id") Long id) throws TodoNotFoundException {Todo found = service.findById(id);return createDTO(found);}private TodoDTO createDTO(Todo model) {TodoDTO dto = new TodoDTO();dto.setId(model.getId());dto.setDescription(model.getDescription());dto.setTitle(model.getTitle());return dto;} }

    返回給客戶端的JSON文檔如下所示:

    {"id":1,"description":"Lorem ipsum","title":"Foo" }

    我們的下一個問題是:

    拋出TodoNotFoundException會發生什么?

    我們的示例應用程序具有一個異常處理程序類,該類處理由控制器類拋出的應用程序特定的異常。 此類具有異常處理程序方法,當拋出TodoNotFoundException時將調用該方法。 此方法的實現將新的日志消息寫入日志文件,并確保將HTTP狀態代碼404發送回客戶端。

    RestErrorHandler類的相關部分如下所示:

    import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus;@ControllerAdvice public class RestErrorHandler {private static final Logger LOGGER = LoggerFactory.getLogger(RestErrorHandler.class);@ExceptionHandler(TodoNotFoundException.class)@ResponseStatus(HttpStatus.NOT_FOUND)public void handleTodoNotFoundException(TodoNotFoundException ex) {LOGGER.debug("handling 404 error on a todo entry");} }

    我們必須為此控制器方法編寫兩個單元測試:

  • 我們必須編寫一個測試,以確保在未找到todo條目時,我們的應用程序能夠正常運行。
  • 我們必須編寫一個測試,以在找到待辦事項條目時驗證是否向客戶端返回了正確的數據。
  • 讓我們看看如何編寫這些測試。

    測試1:找不到待辦事項條目

    首先,當找不到待辦事項時,我們必須確保我們的應用程序正常運行。 我們可以按照以下步驟編寫一個單元測試來確保這一點:

  • 將模擬對象配置為在調用其findById()方法且請求的待辦事項條目的ID為1L時引發TodoNotFoundException 。
  • 執行GET請求以獲取url'/ api / todo / 1'。
  • 驗證是否返回了HTTP狀態代碼404。
  • 確保使用正確的方法參數(1L)僅調用一次TodoService接口的findById()方法。
  • 驗證在此測試期間沒有調用TodoService接口的其他方法。
  • 我們的單元測試的源代碼如下所示:

    import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc;import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {TestContext.class, WebAppContext.class}) @WebAppConfiguration public class TodoControllerTest {private MockMvc mockMvc;@Autowiredprivate TodoService todoServiceMock;//Add WebApplicationContext field here.//The setUp() method is omitted.@Testpublic void findById_TodoEntryNotFound_ShouldReturnHttpStatusCode404() throws Exception {when(todoServiceMock.findById(1L)).thenThrow(new TodoNotFoundException(""));mockMvc.perform(get("/api/todo/{id}", 1L)).andExpect(status().isNotFound());verify(todoServiceMock, times(1)).findById(1L);verifyNoMoreInteractions(todoServiceMock);} }

    測試2:找到Todo條目

    其次,我們必須編寫一個測試,以確保在找到請求的待辦事項條目時返回正確的數據。 我們可以按照以下步驟編寫測試來確保這一點:

  • 創建Todo對象,該對象在調用我們的service方法時返回。 我們使用測試數據生成器創建此對象。
  • 配置我們的模擬對象以在使用方法參數1L調用其findById()方法時返回創建的Todo對象。
  • 執行GET請求以獲取url'/ api / todo / 1'。
  • 驗證是否返回HTTP狀態代碼200。
  • 確認響應的內容類型為“ application / json”,其字符集為“ UTF-8”。
  • 通過使用JsonPath表達式$ .id獲取待辦事項的ID ,并驗證ID為1。
  • 使用JsonPath表達式$ .description獲取待辦事項的描述 ,并驗證該描述是否為“ Lorem ipsum”。
  • 通過使用JsonPath表達式$ .title獲取待辦事項的標題 ,并驗證標題為“ Foo”。
  • 確保使用正確的方法參數(1L)僅調用一次TodoService接口的findById()方法。
  • 驗證測試期間未調用模擬對象的其他方法。
  • 我們的單元測試的源代碼如下所示:

    import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc;import static org.hamcrest.Matchers.is; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {TestContext.class, WebAppContext.class}) @WebAppConfiguration public class TodoControllerTest {private MockMvc mockMvc;@Autowiredprivate TodoService todoServiceMock;//Add WebApplicationContext field here.//The setUp() method is omitted.@Testpublic void findById_TodoEntryFound_ShouldReturnFoundTodoEntry() throws Exception {Todo found = new TodoBuilder().id(1L).description("Lorem ipsum").title("Foo").build();when(todoServiceMock.findById(1L)).thenReturn(found);mockMvc.perform(get("/api/todo/{id}", 1L)).andExpect(status().isOk()).andExpect(content().contentType(TestUtil.APPLICATION_JSON_UTF8)).andExpect(jsonPath("$.id", is(1))).andExpect(jsonPath("$.description", is("Lorem ipsum"))).andExpect(jsonPath("$.title", is("Foo")));verify(todoServiceMock, times(1)).findById(1L);verifyNoMoreInteractions(todoServiceMock);} }

    添加新的待辦事項

    第三種控制器方法將新的待辦事項條目添加到數據庫,并返回添加的待辦事項條目的信息。 讓我們繼續前進,了解它是如何實現的。

    預期行為

    通過執行以下步驟來實現向數據庫添加新的待辦事項條目的控制器方法:

  • 它處理發送到url'/ api / todo'的POST請求。
  • 它驗證作為方法參數給出的TodoDTO對象。 如果驗證失敗,則拋出MethodArgumentNotValidException 。
  • 它通過調用TodoService接口的add()方法向數據庫添加一個新的todo條目,并將TodoDTO對象作為方法參數傳遞。 此方法將新的待辦事項添加到數據庫,并返回添加的待辦事項。
  • 它將創建的Todo對象轉換為TodoDTO對象。
  • 它返回TodoDTO對象。
  • 我們的控制器方法的源代碼如下所示:

    import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*;import javax.validation.Valid;@Controller public class TodoController {private TodoService service;@RequestMapping(value = "/api/todo", method = RequestMethod.POST)@ResponseBodypublic TodoDTO add(@Valid @RequestBody TodoDTO dto) {Todo added = service.add(dto);return createDTO(added);}private TodoDTO createDTO(Todo model) {TodoDTO dto = new TodoDTO();dto.setId(model.getId());dto.setDescription(model.getDescription());dto.setTitle(model.getTitle());return dto;} }

    TodoDTO類是一個簡單的DTO類,其源代碼如下所示:

    import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.NotEmpty;public class TodoDTO {private Long id;@Length(max = 500)private String description;@NotEmpty@Length(max = 100)private String title;//Constructor and other methods are omitted. }

    如我們所見,該類聲明了以下三個約束條件:

  • 的描述的最大長度為500個字符。
  • 待辦事項的標題不能為空。
  • 標題的最大長度為100個字符。
  • 如果驗證失敗,我們的錯誤處理程序組件將確保

  • HTTP狀態代碼400返回到客戶端。
  • 驗證錯誤將作為JSON文檔返回給客戶端。
  • 因為我已經寫了一篇博客文章 ,描述了我們如何向REST API添加驗證,所以本文中沒有討論錯誤處理程序組件的實現。

    但是,如果驗證失敗,我們需要知道將哪種JSON文檔返回給客戶端。 該信息在下面給出。

    如果TodoDTO對象的標題和描述太長,則會將以下JSON文檔返回給客戶端:

    {"fieldErrors":[{"path":"description","message":"The maximum length of the description is 500 characters."},{"path":"title","message":"The maximum length of the title is 100 characters."}] }

    注意 :Spring MVC不保證字段錯誤的順序。 換句話說,場錯誤以隨機順序返回。 在為該控制器方法編寫單元測試時,必須考慮到這一點。

    另一方面,如果驗證沒有失敗,那么我們的控制器方法將以下JSON文檔返回給客戶端:

    {"id":1,"description":"description","title":"todo" }

    我們必須為此控制器方法編寫兩個單元測試:

  • 我們必須編寫一個測試,以確保驗證失敗時我們的應用程序能夠正常運行。
  • 我們必須編寫一個測試,以確保在將新的待辦事項添加到數據庫時,我們的應用程序能夠正常運行。
  • 讓我們找出如何編寫這些測試。

    測試1:驗證失敗

    我們的第一個測試確保當添加的todo條目的驗證失敗時,我們的應用程序可以正常運行。 我們可以按照以下步驟編寫此測試:

  • 創建一個具有101個字符的標題 。
  • 創建一個包含501個字符的描述 。
  • 使用我們的測試數據構建器創建一個新的TodoDTO對象。 設置對象的標題和描述 。
  • 執行POST請求以發送url'/ api / todo'。 將請求的內容類型設置為“ application / json”。 將請求的字符集設置為“ UTF-8”。 將創建的TodoDTO對象轉換為JSON字節并將其發送到請求的正文中。
  • 驗證是否返回了HTTP狀態代碼400。
  • 驗證響應的內容類型為“ application / json”,并且其內容類型為“ UTF-8”。
  • 通過使用JsonPath表達式$ .fieldErrors提取字段錯誤,并確保返回兩個字段錯誤。
  • 通過使用JsonPath表達式$ .fieldErrors [*]。path獲取所有可用路徑,并確保找到有關title和description字段的字段錯誤。
  • 通過使用JsonPath表達式$ .fieldErrors [*]。message來獲取所有可用的錯誤消息,并確保找到有關標題和描述字段的錯誤消息。
  • 驗證測試期間未調用模擬對象的方法。
  • 我們的單元測試的源代碼如下所示:

    import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc;import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.hasSize; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {TestContext.class, WebAppContext.class}) @WebAppConfiguration public class TodoControllerTest {private MockMvc mockMvc;@Autowiredprivate TodoService todoServiceMock;//Add WebApplicationContext field here.//The setUp() method is omitted.@Testpublic void add_TitleAndDescriptionAreTooLong_ShouldReturnValidationErrorsForTitleAndDescription() throws Exception {String title = TestUtil.createStringWithLength(101);String description = TestUtil.createStringWithLength(501);TodoDTO dto = new TodoDTOBuilder().description(description).title(title).build();mockMvc.perform(post("/api/todo").contentType(TestUtil.APPLICATION_JSON_UTF8).content(TestUtil.convertObjectToJsonBytes(dto))).andExpect(status().isBadRequest()).andExpect(content().contentType(TestUtil.APPLICATION_JSON_UTF8)).andExpect(jsonPath("$.fieldErrors", hasSize(2))).andExpect(jsonPath("$.fieldErrors[*].path", containsInAnyOrder("title", "description"))).andExpect(jsonPath("$.fieldErrors[*].message", containsInAnyOrder("The maximum length of the description is 500 characters.","The maximum length of the title is 100 characters.")));verifyZeroInteractions(todoServiceMock);} }

    我們的單元測試使用TestUtil類的兩個靜態方法。 下面介紹了這些方法:

    • createStringWithLength(int length)方法使用給定的長度創建一個新的String對象,并返回創建的對象。
    • convertObjectToJsonBytes(Object object)方法將作為方法參數給出的對象轉換為JSON文檔,并將該文檔的內容作為字節數組返回 。

    TestUtil類的源代碼如下所示:

    import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.http.MediaType;import java.io.IOException; import java.nio.charset.Charset;public class TestUtil {public static final MediaType APPLICATION_JSON_UTF8 = new MediaType(MediaType.APPLICATION_JSON.getType(), MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8"));public static byte[] convertObjectToJsonBytes(Object object) throws IOException {ObjectMapper mapper = new ObjectMapper();mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);return mapper.writeValueAsBytes(object);}public static String createStringWithLength(int length) {StringBuilder builder = new StringBuilder();for (int index = 0; index < length; index++) {builder.append("a");}return builder.toString();} }

    測試2:Todo條目已添加到數據庫

    第二個單元測試確保將新的待辦事項添加到數據庫時,控制器能夠正常工作。 我們可以按照以下步驟編寫此測試:

  • 使用我們的測試數據構建器創建一個新的TodoDTO對象。 在標題和說明字段中設置“合法”值。
  • 創建一個Todo對象,該對象在調用TodoService接口的add()方法時返回。
  • 配置我們的模擬對象,使其在調用其add()方法并將TodoDTO對象作為參數時返回創建的Todo對象。
  • 執行POST請求以發送url'/ api / todo'。 將請求的內容類型設置為“ application / json”。 將請求的字符集設置為“ UTF-8”。 將創建的TodoDTO對象轉換為JSON字節并將其發送到請求的正文中。
  • 驗證是否返回HTTP狀態代碼200。
  • 驗證響應的內容類型為“ application / json”,并且其內容類型為“ UTF-8”。
  • 使用JsonPath表達式$ .id獲取返回的待辦事項條目的ID ,并驗證ID為1。
  • 使用JsonPath表達式$ .description獲取返回的待辦事項的描述 ,并驗證該描述是否為“描述”。
  • 通過使用JsonPath表達式$ .title獲取返回的待辦事項條目的標題 ,并確保標題為“ title”。
  • 創建一個ArgumentCaptor對象,該對象可以捕獲TodoDTO對象。
  • 驗證TodoService接口的add()方法僅被調用一次,并捕獲作為參數給定的對象。
  • 驗證測試期間未調用模擬對象的其他方法。
  • 驗證捕獲的TodoDTO對象的ID為null。
  • 驗證所捕獲的TodoDTO對象的描述是“說明”。
  • 驗證捕獲TodoDTO對象的標題是“冠軍”。
  • 我們的單元測試的源代碼如下所示:

    import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc;import static junit.framework.Assert.assertNull; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {TestContext.class, WebAppContext.class}) @WebAppConfiguration public class TodoControllerTest {private MockMvc mockMvc;@Autowiredprivate TodoService todoServiceMock;//Add WebApplicationContext field here.//The setUp() method is omitted.@Testpublic void add_NewTodoEntry_ShouldAddTodoEntryAndReturnAddedEntry() throws Exception {TodoDTO dto = new TodoDTOBuilder().description("description").title("title").build();Todo added = new TodoBuilder().id(1L).description("description").title("title").build();when(todoServiceMock.add(any(TodoDTO.class))).thenReturn(added);mockMvc.perform(post("/api/todo").contentType(TestUtil.APPLICATION_JSON_UTF8).content(TestUtil.convertObjectToJsonBytes(dto))).andExpect(status().isOk()).andExpect(content().contentType(TestUtil.APPLICATION_JSON_UTF8)).andExpect(jsonPath("$.id", is(1))).andExpect(jsonPath("$.description", is("description"))).andExpect(jsonPath("$.title", is("title")));ArgumentCaptor<TodoDTO> dtoCaptor = ArgumentCaptor.forClass(TodoDTO.class);verify(todoServiceMock, times(1)).add(dtoCaptor.capture());verifyNoMoreInteractions(todoServiceMock);TodoDTO dtoArgument = dtoCaptor.getValue();assertNull(dtoArgument.getId());assertThat(dtoArgument.getDescription(), is("description"));assertThat(dtoArgument.getTitle(), is("title"));} }

    摘要

    現在,我們已經使用Spring MVC Test框架為REST API編寫了單元測試。 本教程教會了我們四件事:

    • 我們學習了為控制器方法編寫單元測試,這些方法從數據庫中讀取信息。
    • 我們學習了為控制器方法編寫單元測試,這些方法將信息添加到數據庫中。
    • 我們了解了如何將DTO對象轉換為JSON字節并將轉換結果發送到請求正文中。
    • 我們學習了如何使用JsonPath表達式編寫JSON文檔的斷言。

    與往常一樣,此博客文章的示例應用程序可在Github上獲得 。 我建議您檢查一下,因為它有很多單元測試,而本博客文章中未涉及。

    參考: Spring MVC控制器的單元測試: Petri Kainulainen博客上的JCG合作伙伴 Petri Kainulainen提供的REST API 。

    翻譯自: https://www.javacodegeeks.com/2013/08/unit-testing-of-spring-mvc-controllers-rest-api.html

    總結

    以上是生活随笔為你收集整理的Spring MVC控制器的单元测试:REST API的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。