gpt4 book ai didi

java - 如何将 @WebMvcTest 用于单元测试 POST 方法?

转载 作者:行者123 更新时间:2023-11-30 07:44:18 25 4
gpt4 key购买 nike

我正在使用 Spring Boot 和 Mockito 运行单元测试,并且正在测试 RESTful 服务。当我尝试测试 GET 方法时它成功运行,但是当我尝试测试 POST 方法时它失败了。我应该怎么做才能解决这个问题?提前致谢!

这是 REST Controller 的代码:

package com.dgs.restfultesting.controller;

import java.net.URI;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import com.dgs.restfultesting.business.ItemBusinessService;
import com.dgs.restfultesting.model.Item;

@RestController
public class ItemController {

@Autowired
private ItemBusinessService businessService;

@GetMapping("/all-items-from-database")
public List<Item> retrieveAllItems() {
return businessService.retrieveAllItems();
}

@PostMapping("/items")
public Item addItem(@RequestBody Item item) {
Item savedItem = businessService.addAnItem(item);

return savedItem;
}
}

业务层:

package com.dgs.restfultesting.business;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.dgs.restfultesting.data.ItemRepository;
import com.dgs.restfultesting.model.Item;

@Component
public class ItemBusinessService {

@Autowired
private ItemRepository repository;

public Item retrieveHardcodedItem() {
return new Item(1, "Book", 10, 100);
}

public List<Item> retrieveAllItems() {

List<Item> items = repository.findAll();

for (Item item : items) {
item.setValue(item.getPrice() * item.getQuantity());
}

return items;
}

public Item addAnItem(Item item) {
return repository.save(item);
}
}

项目 Controller 测试:

package com.dgs.restfultesting.controller;

import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import java.util.Arrays;

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;

import com.dgs.restfultesting.business.ItemBusinessService;
import com.dgs.restfultesting.model.Item;

@RunWith(SpringRunner.class)
@WebMvcTest(ItemController.class)
public class ItemControllerTest {

@Autowired
private MockMvc mockMvc;

@MockBean
private ItemBusinessService businessService;

@Test
public void retrieveAllItems_basic() throws Exception {

when(businessService.retrieveAllItems()).thenReturn(
Arrays.asList(new Item(2, "iPhone", 1000, 10),
new Item(3, "Huawei", 500, 17)));

RequestBuilder request = MockMvcRequestBuilders
.get("/all-items-from-database")
.accept(MediaType.APPLICATION_JSON);

MvcResult result = mockMvc.perform(request)
.andExpect(status().isOk())
.andExpect(content().json("[{id:2, name:iPhone, price:1000}, {id:3, name:Huawei, price:500}]")) // This will return an array back, so this data should be within an array
.andReturn();
}

@Test
public void createItem() throws Exception {
RequestBuilder request = MockMvcRequestBuilders
.post("/items")
.accept(MediaType.APPLICATION_JSON)
.content("{\"id\":1,\"name\":\"Book\",\"price\":10,\"quantity\":100}")
.contentType(MediaType.APPLICATION_JSON);

MvcResult result = mockMvc.perform(request)
.andExpect(status().isCreated())
.andExpect(header().string("location", containsString("/item/")))
.andReturn();
}
}

测试 retrieveAllItems_basic() 方法没有问题,但是当我尝试为 createItem() 方法运行 JUnit 测试时,它不起作用,我得到:java.lang.AssertionError: Status expected:< 201> 但是是:<200>

这是我在控制台中收到的内容:

MockHttpServletRequest:
HTTP Method = POST
Request URI = /items
Parameters = {}
Headers = {Content-Type=[application/json], Accept=[application/json]}
Body = <no character encoding set>
Session Attrs = {}

Handler:
Type = com.dgs.restfultesting.controller.ItemController
Method = public com.dgs.restfultesting.model.Item com.dgs.restfultesting.controller.ItemController.addItem(com.dgs.restfultesting.model.Item)

Async:
Async started = false
Async result = null

Resolved Exception:
Type = null

ModelAndView:
View name = null
View = null
Model = null

FlashMap:
Attributes = null

MockHttpServletResponse:
Status = 200
Error message = null
Headers = {}
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
2018-10-07 17:53:51.457 INFO 55300 --- [ Thread-3] o.s.w.c.s.GenericWebApplicationContext : Closing org.springframework.web.context.support.GenericWebApplicationContext@71075444: startup date [Sun Oct 07 17:53:48 EEST 2018]; root of context hierarchy

更新----------------------------

我尝试这样设置位置:item/id。

这是 Controller 的代码:

@PostMapping("/items")
public ResponseEntity<Object> addItem(@RequestBody Item item) {
Item savedItem = businessService.addAnItem(item);
HttpHeaders httpHeaders = new HttpHeaders();
UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.newInstance();

UriComponents uriComponents =
uriComponentsBuilder.path("/item/{id}").buildAndExpand(savedItem.getId());
httpHeaders.setLocation(uriComponents.toUri());

return new ResponseEntity<>(savedItem, httpHeaders, HttpStatus.CREATED);
}

这是测试代码:

@Test
public void createItem() throws Exception {

RequestBuilder request = MockMvcRequestBuilders
.post("/items")
.accept(MediaType.APPLICATION_JSON)
.content("{\"id\":1,\"name\":\"Book\",\"price\":10,\"quantity\":100}")
.contentType(MediaType.APPLICATION_JSON);

MvcResult result = mockMvc.perform(request)
.andExpect(status().isCreated())
.andExpect(header().string("location", containsString("/item/1")))
.andReturn();
}

当我为 createItem() 方法运行 JUnit 测试时,我收到此错误:org.springframework.web.util.NestedServletException:请求处理失败;嵌套异常是 java.lang.NullPointerException

最佳答案

从您的 Controller 返回 201:因为您的断言测试期望通过使用 created 状态得到 201 但您的 Controller 返回 200(OK) .

   @PostMapping("/items")
public ResponseEntity<?> addItem(@RequestBody Item item) {
Item savedItem = itemBusinessService.addAnItem(item);

return new ResponseEntity<>(savedItem, HttpStatus.CREATED);
}

或者修改您的测试以检查状态 OK(200)。如果您不想断言“位置”,请更新您的测试。

 @Test
public void createItem() throws Exception {
RequestBuilder request = MockMvcRequestBuilders
.post("/items")
.accept(MediaType.APPLICATION_JSON)
.content("{\"id\":1,\"name\":\"Book\",\"price\":10,\"quantity\":100}")
.contentType(MediaType.APPLICATION_JSON);

MvcResult result = mockMvc.perform(request)
.andExpect(status().isOk()).andReturn();
}

更新--允许响应中的位置 header

如果您希望 “location” 从 header 返回,则修改您的 Controller 和下面的测试用例以检查 header 中的位置。

第 1 步:在 Controller 的添加项方法中,添加位置 uri 并返回。

 @PostMapping("/items")
public ResponseEntity<?> addItem(@RequestBody Item item) {
Item savedItem = businessService.addAnItem(item);
HttpHeaders httpHeaders = new HttpHeaders();
UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.newInstance();

UriComponents uriComponents =
uriComponentsBuilder.path("/item/").buildAndExpand("/item/");
httpHeaders.setLocation(uriComponents.toUri());
return new ResponseEntity<>(savedItem, httpHeaders, HttpStatus.CREATED);
}

第 2 步:现在您的测试将按照您的预期断言 "location"

 @Test
public void createItem() throws Exception {
RequestBuilder request = MockMvcRequestBuilders
.post("/items")
.accept(MediaType.APPLICATION_JSON)
.content("{\"id\":1,\"name\":\"Book\",\"price\":10,\"quantity\":100}")
.contentType(MediaType.APPLICATION_JSON);

MvcResult result = mockMvc.perform(request)
.andExpect(status().isCreated())
.andExpect(header().string("location", containsString("/item/")))
.andReturn();
}

关于java - 如何将 @WebMvcTest 用于单元测试 POST 方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52689731/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com