2

Я пытаюсь использовать TestRestTemplate в Integration-Test Spring Boot Application Integration-Test, чтобы сделать запрос в репозиторий REST Spring Data REST.TestTestplate Spring Boot с HATEOAS PagedResources

Ответ в браузере имеет вид:

{ 
"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 
} 
} 

Это испытание:

@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); 
    } 
    } 
} 

Проблема в том, что я не получаю содержание. Интересно, что есть метаданные (пейджинговая информация).

My TestConfig обнаружен, но я думаю, что он не использует «halJacksonHttpMessageConverter» (который я получил отсюда: https://github.com/bijukunjummen/hateoas-sample/blob/master/src/test/java/univ/HALRestTemplateIntegrationTests.java). Вот почему я использовал messageConverters(), а не «дополнительныеMessageConverters()» (безрезультатно).

Вот лог:

m.m.a.RequestResponseBodyMethodProcessor : Written [PagedResource { content: [Resource { content: [email protected], links: [<http://localhost:51708/apiv1/data/users/1>;rel="self", <http://localhost:51708/apiv1/data/users/1>;rel="logisUser"] }, Resource { content: [email protected], links: [<http://localhost:51708/apiv1/data/users/2>;rel="self", <http://localhost:51708/apiv1/data/users/2>;rel="logisUser"] }, Resource { content: [email protected], links: [<http://localhost:51708/apiv1/data/users/3>;rel="self", <http://localhost:51708/apiv1/data/users/3>;rel="logisUser"] }, Resource { content: [email protected], 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.Rep[email protected]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.Rep[email protected]10ad95cd] 
o.s.b.w.f.OrderedRequestContextFilter : Cleared thread-bound request context: [email protected] 
d.l.a.MyUserRepositoryIntegrationTest : Res : PagedResource { content: [], metadata: Metadata { number: 0, total pages: 1, total elements: 4, size: 20 }, links: [] } 

Идея переопределяя restTemplate Bean приходит из документации: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-rest-templates-test-utility

Любые идеи, как я могу просто сделать некоторые REST звонки и получить ответ как объект для мои тесты?

+0

Это может быть полезно: http://stackoverflow.com/questions/38468839/spring-data-rest-consume-list-of-entities-java-hateoas-client –

+0

Я просто попробовал это с ClientHttpRequestInterceptor, но он не работает. Кроме того, я могу получить все данные, выполнив getForEntity с помощью String.class. И проверьте журнал (последний поле с цитатой), который читает «Чтение [..PagedResources <...MyUser>] как« application/hal + json; charset = UTF-8 »' –

ответ

2

я перешел на MockMvc и все работает:

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:

Для тех, кто заинтересован, альтернативное решение, основанное на решении Wellington Souza «s:

Хотя jsonpath действительно мощный, я не нашел способ действительно маршализацию в JSON в реальный объект с MockMvc.

Если вы посмотрите на мой опубликованный вывод JSON, вы заметите, что это не выходной сигнал Spring HAL + JSON по умолчанию. Я изменил свойство data.rest.defaultMediaType на «application/json». С этим я не мог заставить Траверсона работать. Но когда я дезактивировать, что следующие работы:

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<PagedResources<MyUser>> resourceParameterizedTypeReference = // 
     new ParameterizedTypeReference<PagedResources<MyUser>>() { 
     }; 

    final PagedResources<MyUser> 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(); 
    } 
} 

(Примечание: не может содержать все импорта и т.д., так как я скопировал это из большего испытания класса.)

«.withParam» работает шаблонные URL-адреса, т. е. те, которые принимают параметры запроса. Если вы попытаетесь выполнить необработанный URL-адрес, он будет терпеть неудачу, потому что ссылка буквально «http://[...]/users {option1, option2, ...}» и, следовательно, не была правильно сформирована.

2

Я сделал аналогичный тест, но я не использую пружинный ботинок. Вероятно, это конфигурация вашего RestTemplate. Кстати, вы пытались использовать реализацию Traverson, а не RestTemplate? Кажется более простым работать с HATEOAS. См. Ниже мой тестовый класс с обоими подходами.

package org.wisecoding.api; 

import org.junit.Test; 

import org.wisecoding.api.domain.User; 
import com.fasterxml.jackson.databind.DeserializationFeature; 
import com.fasterxml.jackson.databind.ObjectMapper; 

import org.springframework.core.ParameterizedTypeReference; 
import org.springframework.hateoas.MediaTypes; 
import org.springframework.hateoas.PagedResources; 
import org.springframework.hateoas.client.Traverson; 
import org.springframework.hateoas.hal.Jackson2HalModule; 
import org.springframework.http.HttpMethod; 
import org.springframework.http.MediaType; 
import org.springframework.http.ResponseEntity; 
import org.springframework.http.converter.HttpMessageConverter; 
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; 
import org.springframework.web.client.RestTemplate; 

import java.net.URI; 
import java.util.ArrayList; 
import java.util.List; 

import static org.springframework.hateoas.client.Hop.rel; 

public class UserApiTest { 


    @Test 
    public void testGetUsersRestTemplate() { 
     final ObjectMapper mapper = new ObjectMapper(); 
     mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 
     mapper.registerModule(new Jackson2HalModule()); 

     final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); 
     converter.setSupportedMediaTypes(MediaType.parseMediaTypes(MediaTypes.HAL_JSON_VALUE)); 
     converter.setObjectMapper(mapper); 

     final List<HttpMessageConverter<?>> list = new ArrayList<HttpMessageConverter<?>>(); 
     list.add(converter); 
     final RestTemplate restTemplate = new RestTemplate(list); 

     final String authorsUrl = "http://localhost:8080/apiv1/users"; 

     final ResponseEntity<PagedResources<User>> responseEntity = restTemplate.exchange(authorsUrl, HttpMethod.GET, null, new ParameterizedTypeReference<PagedResources<User>>() {}); 
     final PagedResources<User> resources = responseEntity.getBody(); 
     final List<User> users = new ArrayList(resources.getContent()); 
    } 


    @Test 
    public void testGetUsersTraverson() throws Exception { 
     final Traverson traverson = new Traverson(new URI("http://localhost:8080/apiv1"), MediaTypes.HAL_JSON); 
     final ParameterizedTypeReference<PagedResources<User>> resourceParameterizedTypeReference = new ParameterizedTypeReference<PagedResources<User>>() {}; 
     final PagedResources<User> resources = traverson.follow(rel("users")).toObject(resourceParameterizedTypeReference); 
     final List<User> users = new ArrayList(resources.getContent()); 
    } 
} 

А также, pom.xml в случае, если ваши зависимости не соответствует:

<?xml version="1.0" encoding="UTF-8"?> 
<project xmlns="http://maven.apache.org/POM/4.0.0" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 

    <modelVersion>4.0.0</modelVersion> 
    <packaging>war</packaging> 
    <groupId>org.wisecoding</groupId> 
    <version>0.1-SNAPSHOT</version> 
    <artifactId>user-demo-data-rest</artifactId> 


    <properties> 
     <spring.version>4.2.6.RELEASE</spring.version> 
     <slf4j.version>1.7.1</slf4j.version> 
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
    </properties> 


    <build> 
     <plugins> 
      <plugin> 
       <groupId>org.apache.maven.plugins</groupId> 
       <artifactId>maven-resources-plugin</artifactId> 
       <configuration> 
        <encoding>UTF-8</encoding> 
       </configuration> 
      </plugin> 
      <plugin> 
       <groupId>org.eclipse.jetty</groupId> 
       <artifactId>jetty-maven-plugin</artifactId> 
       <version>9.0.4.v20130625</version> 
      </plugin> 
     </plugins> 
    </build> 


    <dependencies> 

     <dependency> 
      <groupId>com.jayway.jsonpath</groupId> 
      <artifactId>json-path</artifactId> 
      <version>2.2.0</version> 
      <scope>test</scope> 
     </dependency> 

     <dependency> 
      <groupId>com.fasterxml.jackson.datatype</groupId> 
      <artifactId>jackson-datatype-json-org</artifactId> 
      <version>2.7.5</version> 
     </dependency> 

     <dependency> 
      <groupId>com.fasterxml.jackson.core</groupId> 
      <artifactId>jackson-databind</artifactId> 
      <version>2.6.7</version> 
     </dependency> 

     <dependency> 
      <groupId>org.springframework.data</groupId> 
      <artifactId>spring-data-rest-webmvc</artifactId> 
      <version>2.5.6.RELEASE</version> 
      <exclusions> 
       <exclusion> 
        <groupId>org.aspectj</groupId> 
        <artifactId>aspectjrt</artifactId> 
       </exclusion> 
      </exclusions> 
     </dependency> 

     <dependency> 
      <groupId>org.springframework.data</groupId> 
      <artifactId>spring-data-jpa</artifactId> 
      <version>1.10.1.RELEASE</version> 
     </dependency> 

     <dependency> 
      <groupId>org.springframework</groupId> 
      <artifactId>spring-context</artifactId> 
      <version>${spring.version}</version> 
     </dependency> 

     <dependency> 
      <groupId>org.springframework</groupId> 
      <artifactId>spring-web</artifactId> 
      <version>${spring.version}</version> 
     </dependency> 

     <dependency> 
      <groupId>org.springframework</groupId> 
      <artifactId>spring-webmvc</artifactId> 
      <version>${spring.version}</version> 
     </dependency> 

     <dependency> 
      <groupId>org.springframework</groupId> 
      <artifactId>spring-test</artifactId> 
      <version>${spring.version}</version> 
      <scope>test</scope> 
     </dependency> 

     <dependency> 
      <groupId>javax.servlet</groupId> 
      <artifactId>javax.servlet-api</artifactId> 
      <version>3.1.0</version> 
     </dependency> 


     <dependency> 
      <groupId>org.slf4j</groupId> 
      <artifactId>slf4j-api</artifactId> 
      <version>${slf4j.version}</version> 
     </dependency> 

     <dependency> 
      <groupId>ch.qos.logback</groupId> 
      <artifactId>logback-classic</artifactId> 
      <version>1.0.13</version> 
      <scope>runtime</scope> 
     </dependency> 

     <dependency> 
      <groupId>junit</groupId> 
      <artifactId>junit</artifactId> 
      <version>4.11</version> 
      <scope>test</scope> 
     </dependency> 


     <dependency> 
      <groupId>org.hibernate</groupId> 
      <artifactId>hibernate-entitymanager</artifactId> 
      <version>4.2.3.Final</version> 
     </dependency> 
     <dependency> 
      <groupId>org.springframework</groupId> 
      <artifactId>spring-jdbc</artifactId> 
      <version>${spring.version}</version> 
     </dependency> 

     <dependency> 
      <groupId>hsqldb</groupId> 
      <artifactId>hsqldb</artifactId> 
      <version>1.8.0.10</version> 
     </dependency> 

    </dependencies> 


    <repositories> 
     <repository> 
      <id>central</id> 
      <url>http://central.maven.org/maven2/</url> 
      <snapshots> 
       <enabled>false</enabled> 
      </snapshots> 
     </repository> 
    </repositories> 

</project> 
+0

Я действительно не хочу добавлять другую внешнюю библиотеку. Возможно, вы правы, что это проблема с конфигурацией RestTemplate, но обратите внимание, что я не использую необработанный RestTemplate, а Spring Boot TestRestTemplate, который должен быть предварительно настроен. –

+0

ОК, мой плохой, я думал, что Traverson был сторонником Lib. Я пробовал это, и он отлично работает с некоторыми изменениями: 1) Как описано в [1], я изменил тип носителя по умолчанию. Если вы посмотрите на json, который я включил, он выглядит иначе, чем стандартный. Я не нашел способа заставить его работать с этим, только при переключении на hal + json. 2) Это шаблонная ссылка, поэтому мне нужно: «.follow (Hop.rel (« logisUsers ») .Parameter (« sort »,« username, asc »))' 3) аутентификация: .withHeaders (userHeaders) [1] http://stackoverflow.com/questions/41678786/spring-data-rest-switch-between-haljson-and-plain-json –

 Смежные вопросы

  • Нет связанных вопросов^_^