I'm trying to use the TestRestTemplate in my Spring Boot Application's Integration-Test, to make a request to a Spring Data REST Repository.
The response in the browser has the form:
{
"links": [
{
"rel": "self",
"href": "http://localhost:8080/apiv1/data/users"
},
{
"rel": "profile",
"href": "http://localhost:8080/apiv1/data/profile/users"
},
{
"rel": "search",
"href": "http://localhost:8080/apiv1/data/users/search"
}
],
"content": [
{
"username": "admin",
"enabled": true,
"firstName": null,
"lastName": null,
"permissions": [ ],
"authorities": [
"ROLE_ADMIN"
],
"accountNonExpired": true,
"accountNonLocked": true,
"credentialsNonExpired": true,
"content": [ ],
"links": [
{
"rel": "self",
"href": "http://localhost:8080/apiv1/data/users/1"
},
{
"rel": "myUser",
"href": "http://localhost:8080/apiv1/data/users/1"
},
{
"rel": "mandant",
"href": "http://localhost:8080/apiv1/data/users/1/mandant"
}
]
},
{
"username": "dba",
"enabled": true,
"firstName": null,
"lastName": null,
"permissions": [ ],
"authorities": [
"ROLE_DBA"
],
"accountNonExpired": true,
"accountNonLocked": true,
"credentialsNonExpired": true,
"content": [ ],
"links": [
{
"rel": "self",
"href": "http://localhost:8080/apiv1/data/users/2"
},
{
"rel": "myUser",
"href": "http://localhost:8080/apiv1/data/users/2"
},
{
"rel": "mandant",
"href": "http://localhost:8080/apiv1/data/users/2/mandant"
}
]
},
{
"username": "user",
"enabled": true,
"firstName": null,
"lastName": null,
"permissions": [ ],
"authorities": [
"ROLE_USER"
],
"accountNonExpired": true,
"accountNonLocked": true,
"credentialsNonExpired": true,
"content": [ ],
"links": [
{
"rel": "self",
"href": "http://localhost:8080/apiv1/data/users/3"
},
{
"rel": "myUser",
"href": "http://localhost:8080/apiv1/data/users/3"
},
{
"rel": "mandant",
"href": "http://localhost:8080/apiv1/data/users/3/mandant"
}
]
}
],
"page": {
"size": 20,
"totalElements": 3,
"totalPages": 1,
"number": 0
}
}
This is the test:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@ActiveProfiles("unittest")
public class MyUserRepositoryIntegrationTest {
private static Logger logger = LoggerFactory.getLogger(MyUserRepositoryIntegrationTest.class);
private static final int NUM_USERS = 4;
private static final String USER_URL = "/apiv1/data/users";
@Autowired
private TestRestTemplate restTemplate;
@Test
public void listUsers() {
ResponseEntity<PagedResources<MyUser>> response = restTemplate.withBasicAuth("user", "user").exchange(USER_URL,
HttpMethod.GET, null, new ParameterizedTypeReference<PagedResources<MyUser>>() {
});
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
logger.debug("Res : " + response.getBody().toString());
assertThat(response.getBody().getContent().size()).isEqualTo(NUM_USERS);
}
@TestConfiguration
public static class MyTestConfig {
@Autowired
@Qualifier("halJacksonHttpMessageConverter")
private TypeConstrainedMappingJackson2HttpMessageConverter halJacksonHttpMessageConverter;
@Bean
public RestTemplateBuilder restTemplateBuilder() {
return new RestTemplateBuilder().messageConverters(halJacksonHttpMessageConverter);
}
}
}
The Problem is, that I don't get the content. Interestingly, the Metadata (paging-info) is there.
My TestConfig gets detected, but I think it's not using the 'halJacksonHttpMessageConverter' (which I got from here: https://github.com/bijukunjummen/hateoas-sample/blob/master/src/test/java/univ/HALRestTemplateIntegrationTests.java). That's why I used "messageConverters()" and not "additionalMessageConverters()" (to no avail).
Here's the log:
m.m.a.RequestResponseBodyMethodProcessor : Written [PagedResource { content: [Resource { content: at.mycompany.myapp.auth.MyUser@7773211c, links: [<http://localhost:51708/apiv1/data/users/1>;rel="self", <http://localhost:51708/apiv1/data/users/1>;rel="logisUser"] }, Resource { content: at.mycompany.myapp.auth.MyUser@2c96fdee, links: [<http://localhost:51708/apiv1/data/users/2>;rel="self", <http://localhost:51708/apiv1/data/users/2>;rel="logisUser"] }, Resource { content: at.mycompany.myapp.auth.MyUser@1ddfd104, links: [<http://localhost:51708/apiv1/data/users/3>;rel="self", <http://localhost:51708/apiv1/data/users/3>;rel="logisUser"] }, Resource { content: at.mycompany.myapp.auth.MyUser@55d71419, links: [<http://localhost:51708/apiv1/data/users/4>;rel="self", <http://localhost:51708/apiv1/data/users/4>;rel="logisUser"] }], metadata: Metadata { number: 0, total pages: 1, total elements: 4, size: 20 }, links: [<http://localhost:51708/apiv1/data/users>;rel="self", <http://localhost:51708/apiv1/data/profile/users>;rel="profile", <http://localhost:51708/apiv1/data/users/search>;rel="search"] }] as "application/hal+json" using [org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration$ResourceSupportHttpMessageConverter@2f58f492]
o.s.web.servlet.DispatcherServlet : Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
o.s.web.client.RestTemplate : GET request for "http://localhost:51708/apiv1/data/users" resulted in 200 (null)
o.s.web.servlet.DispatcherServlet : Successfully completed request
o.s.web.client.RestTemplate : Reading [org.springframework.hateoas.PagedResources<at.mycompany.myapp.auth.MyUser>] as "application/hal+json;charset=UTF-8" using [org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration$ResourceSupportHttpMessageConverter@10ad95cd]
o.s.b.w.f.OrderedRequestContextFilter : Cleared thread-bound request context: org.apache.catalina.connector.RequestFacade@76e257e2
d.l.a.MyUserRepositoryIntegrationTest : Res : PagedResource { content: [], metadata: Metadata { number: 0, total pages: 1, total elements: 4, size: 20 }, links: [] }
The idea of overriding the restTemplate Bean comes from the docs: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-rest-templates-test-utility
Any Ideas how I can simply make some REST calls and get the answer as an Object for my tests?
I switched to MockMvc and everything works:
EDIT:
For those interested, an alternative solution based on Wellington Souza's solution:
While jsonpath is really powerful, I haven't found a way to really unmarshall the JSON into an actual Object with MockMvc.
If you look at my posted JSON output, you'll notice, that it's not the default Spring Data Rest HAL+JSON output. I changed the property data.rest.defaultMediaType to "application/json". With that, I couldn't get Traverson to work either. But when I deactivate that, the following works:
(Note: Might not contain all imports etc., since I copied this from a larger Test Class.)
The ".withParam" works for templated URLs, i.e., ones that accept query parameters. If you try to follow the raw URL, it will fail, because the link is literally "http://[...]/users{option1,option2,...}" and thus not well-formed.
I did a similar test, but I'm not using spring-boot. Probably is the configuration of your RestTemplate. By the way, have you tried to use the
Traverson
implementation rather thanRestTemplate
? It's seems more simple to work with HATEOAS. See bellow my test class with both approaches.And also, the
pom.xml
in case your dependencies does not match: