Spring Boot's TestRestTemplate with HATEOAS PagedResources

后端 未结 2 706
一整个雨季
一整个雨季 2021-01-13 20:55

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 br

2条回答
  •  猫巷女王i
    2021-01-13 21:51

    I switched to MockMvc and everything works:

    import static org.hamcrest.Matchers.hasSize;
    import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;    
    
    @RunWith(SpringRunner.class)
    @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
    @ActiveProfiles("unittest")
    public class MyUserRepositoryIntegrationTest {
        @Autowired WebApplicationContext context;
        @Autowired FilterChainProxy filterChain;
        MockMvc mvc;
    
        @Before
        public void setupTests() {
        this.mvc = MockMvcBuilders.webAppContextSetup(context).addFilters(filterChain).build();
    
        @Test
        public void listUsers() throws Exception {
          HttpHeaders headers = new HttpHeaders();
          headers.add(HttpHeaders.ACCEPT, MediaTypes.HAL_JSON_VALUE);
          headers.add(HttpHeaders.AUTHORIZATION, "Basic " + new String(Base64.encode(("user:user").getBytes())));
    
          mvc.perform(get(USER_URL).headers(headers))
              .andExpect(content().contentTypeCompatibleWith(MediaTypes.HAL_JSON))
              .andExpect(status().isOk())
              .andExpect(jsonPath("$.content", hasSize(NUM_USERS)));
        }
    }
    

    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:

    import static org.assertj.core.api.Assertions.assertThat;
    import static org.hamcrest.Matchers.hasSize;
    import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
    
    import org.springframework.hateoas.MediaTypes;
    import org.springframework.hateoas.PagedResources;
    import org.springframework.hateoas.client.Hop;
    import org.springframework.hateoas.client.Traverson;
    import org.springframework.http.HttpHeaders;
    import org.springframework.security.crypto.codec.Base64;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
    @ActiveProfiles("unittest")
    public class MyUserRepositoryIntegrationTest {
      private static HttpHeaders userHeaders;
      private static HttpHeaders adminHeaders;
    
      @LocalServerPort
      private int port;
    
      @BeforeClass
      public static void setupTests() {
        MyUserRepositoryIntegrationTest.userHeaders = new HttpHeaders();
        MyUserRepositoryIntegrationTest.userHeaders.add(HttpHeaders.ACCEPT, MediaTypes.HAL_JSON_VALUE);
        MyUserRepositoryIntegrationTest.userHeaders.add(HttpHeaders.AUTHORIZATION,
            "Basic " + new String(Base64.encode(("user:user").getBytes())));
    
        MyUserRepositoryIntegrationTest.adminHeaders = new HttpHeaders();
        MyUserRepositoryIntegrationTest.adminHeaders.add(HttpHeaders.ACCEPT, MediaTypes.HAL_JSON_VALUE);
        MyUserRepositoryIntegrationTest.adminHeaders.add(HttpHeaders.AUTHORIZATION,
            "Basic " + new String(Base64.encode(("admin:admin").getBytes())));
      }
    
      @Test
      public void listUsersSorted() throws Exception {
        final ParameterizedTypeReference> resourceParameterizedTypeReference = //
            new ParameterizedTypeReference>() {
            };
    
        final PagedResources actual = new Traverson(new URI("http://localhost:" + port + "/apiv1/data"),
            MediaTypes.HAL_JSON)//
                .follow(Hop.rel("myUsers").withParameter("sort", "username,asc"))//
                .withHeaders(userHeaders)//
                .toObject(resourceParameterizedTypeReference);
    
        assertThat(actual.getContent()).isNotNull().isNotEmpty();
        assertThat(actual.getContent()//
            .stream()//
            .map(user -> user.getUsername())//
            .collect(Collectors.toList())//
        ).isSorted();
      }
    }
    

    (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.

提交回复
热议问题