Le problème
Je suis nouveau dans le monde de Spring et j'essaie d'écrire quelques tests unitaires pour mon contrôleur REST. Je teste manuellement avec httpie
o curl
fonctionne bien, cependant, avec @WebMvcTest
des choses étranges se produisent.
Voici ce qui se passe quand je PUT
un nouvel utilisateur par curl
:
$ 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"}
Comme vous pouvez le voir, l'en-tête Content-Type est présent dans la réponse et le corps est bien la nouvelle version de l'application User
.
Voici comment j'essaie de tester la même chose automatiquement :
@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"));
}
}
Mais ce que je comprends, c'est ça :
$ 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)
Que se passe-t-il ? Où est le corps de la MockHttpServletResponse
? Je dois manquer quelque chose, car il semble agir de manière complètement différente.
Autre code au cas où il serait nécessaire
Ma classe de contrôleur générique :
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 ... */
}
L'actuel User
contrôleur :
@RestController
@RequestMapping(path="/users")
public class UserController extends GenericController<User> { }
MISE À JOUR 2020-04-22
Comme suggéré, j'ai retiré les génériques de l'équation, mais cela n'a pas aidé.