gpt4 book ai didi

java - Spring REST Controller 在单元测试中的行为不同

转载 作者:行者123 更新时间:2023-12-01 14:13:55 25 4
gpt4 key购买 nike

问题

我是 Spring 的新手,正在尝试为我的 REST Controller 编写一些单元测试。使用 httpiecurl 手动测试效果很好,但是,使用 @WebMvcTest 时,会发生奇怪的事情。

这是我通过 curl PUT 新用户时发生的情况:

$ curl -v -H'Content-Type: application/json' -d@- localhost:8080/api/users <john_smith.json                                                                                                                                  
* Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> POST /api/users HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.69.1
> Accept: */*
> Content-Type: application/json
> Content-Length: 102
>
* upload completely sent off: 102 out of 102 bytes
* Mark bundle as not supporting multiuse
< HTTP/1.1 200
< Content-Type: application/json
< Transfer-Encoding: chunked
< Date: Sat, 18 Apr 2020 22:29:43 GMT
<
* Connection #0 to host localhost left intact
{"id":1,"firstName":"John","lastName":"Smith","email":"john.smith@example.com","password":"l33tp4ss"}

如您所见,响应中有 Content-Type header ,正文确实是新的 User

以下是我尝试自动测试的方式:

@RunWith(SpringRunner.class)
@WebMvcTest(UserController.class)
public class UserControllerTest {

@Autowired
private MockMvc mvc;

@MockBean
private UserService service;

private final User john = new User("John", "Smith",
"john.smith@example.com",
"s3curep4ss");

@Test
public void givenNoUser_whenCreateUser_thenOk()
throws Exception
{
given(service.create(john)).willReturn(john);

mvc.perform(post("/users")
.contentType(APPLICATION_JSON)
.content(objectToJsonBytes(john)))
.andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON))
.andExpect(jsonPath("$.id", is(0)))
.andDo(document("user"));
}

}

但我得到的是:

$ mvn test
[...]
MockHttpServletRequest:
HTTP Method = POST
Request URI = /users
Parameters = {}
Headers = [Content-Type:"application/json", Content-Length:"103"]
Body = {"id":0,"firstName":"John","lastName":"Smith","email":"john.smith@example.com","password":"s3curep4ss"}
Session Attrs = {}

Handler:
Type = webshop.controller.UserController
Method = webshop.controller.UserController#create(Base)

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 = []
[ERROR] Tests run: 6, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 11.271 s <<< FAILURE! - in webshop.UserControllerTest
[ERROR] givenNoUser_whenCreateUser_thenOk Time elapsed: 0.376 s <<< FAILURE!
java.lang.AssertionError: Content type not set
at webshop.UserControllerTest.givenNoUser_whenCreateUser_thenOk(UserControllerTest.java:70)

发生了什么? MockHttpServletResponse 的正文在哪里?我一定是遗漏了什么,因为它的行为似乎完全不同。


其他代码以备不时之需

我的通用 Controller 类:

public class GenericController<T extends Base>
implements IGenericController<T> {

@Autowired
private IGenericService<T> service;

@Override
@PostMapping(consumes = APPLICATION_JSON_VALUE,
produces = APPLICATION_JSON_VALUE)
public T create(@Valid @RequestBody T entity)
{
return service.create(entity);
}

/* ... Other RequestMethods ... */

}

实际的 User Controller :

@RestController
@RequestMapping(path="/users")
public class UserController extends GenericController<User> { }

2020 年 4 月 22 日更新
正如建议的那样,我将泛型排除在外,但没有帮助。

最佳答案

似乎 @WebMvcTest 注释正在配置一个使用真实实现的 UserService bean,而您的 bean 以某种方式被忽略了。

我们可以尝试以不同的方式创建 UserService bean

@RunWith(SpringRunner.class)
@WebMvcTest(UserController.class)
@Import(UserControllerTest.Config.class)
public class UserControllerTest {

@TestConfiguration
static class Config {

@Primary
@Bean
UserService mockedUserService() {
UserService service = Mockito.mock(UserService.class);
given(service.create(john)).willReturn(UserControllerTest.john());
return service;
}
}

static User john() {
return new User("John", "Smith", "john.smith@example.com", "s3curep4ss");
}

...
}

您还可以将 stub 移动到测试中的 @Before 方法

@Configuration
public class CommonTestConfig {
@Primary
@Bean
UserService mockedUserService() {
return Mockito.mock(UserService.class)
}
}

@RunWith(SpringRunner.class)
@WebMvcTest(UserController.class)
@Import(CommonTestConfig.class)
public class Test1 {
@Autowired
private UserService userService;

@Before
public void setup() {
given(userService.create(any())).willReturn(user1());
}
}

@RunWith(SpringRunner.class)
@WebMvcTest(UserController.class)
@Import(CommonTestConfig.class)
public class Test2 {
@Autowired
private UserService userService;

@Before
public void setup() {
given(userService.create(any())).willReturn(user2());
}
}

关于java - Spring REST Controller 在单元测试中的行为不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61296116/

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