【发布时间】:2020-04-30 15:46:47
【问题描述】:
问题
我是 Spring 新手,正在尝试为我的 REST 控制器编写一些单元测试。使用httpie 或curl 手动测试效果很好,但是使用@WebMvcTest 会发生奇怪的事情。
当我 PUTcurl 的新用户时会发生以下情况:
$ 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 标头,正文确实是新的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 的尸体在哪里?我一定错过了什么,因为它的行为似乎完全不同。
其他代码以备不时之需
我的通用控制器类:
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控制器:
@RestController
@RequestMapping(path="/users")
public class UserController extends GenericController<User> { }
2020 年 4 月 22 日更新
正如建议的那样,我将泛型排除在外,但这并没有帮助。
【问题讨论】:
-
docs.spring.io/spring/docs/current/javadoc-api/org/…,你不使用spring
MediaType类有什么原因吗? -
@ThomasAndolf 啊,谢谢。
_UTF8版本当时正在重新发明轮子,也是不必要的。我现在完全删除了它。但是,这似乎与我的问题无关(我还用正确的MediaType更新了我的问题)。 -
uris 显示不同:/api/users vs /users。这有什么关系吗?
-
我怀疑但我不确定您的模拟是否返回 null。主要是因为你说你想要一个特定的对象,而 java 是按值传递的,所以它想要那个特定的对象而不是任何其他对象。另一方面,您的控制器传递了一个新创建的对象,该对象不是那个特定的值。请检查和调试,看看
service.create(entity)返回什么? -
你能打印出模拟返回的内容吗?或调试并设置调试点并查看模拟返回的内容,以便我可以看到您要发送回的内容。
标签: java spring spring-boot spring-mvc