Я использую Spring Boot 1.4.2 и Jersey (jax-rs) для создания контроллера REST. Я следил за документацией по тестированию контроллеров REST (Тестирование фрагмента Spring MVC). Но мой тест возвращает 404, и я не могу понять, почему. Контроллер здесь упрощен, но проблема остается.

У меня вопрос, как получить статус 200 при запуске теста?

HealthController.java

@Controller
@Path("/health")
public class HealthController {
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Health health() {
        return Health.up().build();
    }
}

Запуск сервера и выполнение запроса дает мне это

%> curl -i http://localhost:8080/health
HTTP/1.1 200 
X-Application-Context: application
Content-Type: application/json
Content-Length: 21
Date: Sun, 27 Nov 2016 15:22:30 GMT

{
  "status" : "UP"
}% 

HealthControllerTest.java

@RunWith(SpringRunner.class)
@WebMvcTest(HealthController.class)
public class HealthControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void health() throws Exception {
        mockMvc.perform(get("/health").accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk()); // 200 expected
    }
}

Вот что я получаю при запуске теста

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.4.2.RELEASE)

2016-11-27 16:22:08.254  INFO 9029 --- [           main] no.avec.controller.HealthControllerTest  : Starting HealthControllerTest on ducati.local with PID 9029 (started by avec in /Users/avec/Projects/RESTdemo)
2016-11-27 16:22:08.257 DEBUG 9029 --- [           main] no.avec.controller.HealthControllerTest  : Running with Spring Boot v1.4.2.RELEASE, Spring v4.3.4.RELEASE
2016-11-27 16:22:08.257  INFO 9029 --- [           main] no.avec.controller.HealthControllerTest  : No active profile set, falling back to default profiles: default
2016-11-27 16:22:09.294  INFO 9029 --- [           main] no.avec.controller.HealthControllerTest  : Started HealthControllerTest in 1.421 seconds (JVM running for 2.132)

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /health
       Parameters = {}
          Headers = {Accept=[application/json]}

Handler:
             Type = org.springframework.web.servlet.resource.ResourceHttpRequestHandler

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = null

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 404
    Error message = null
          Headers = {}
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

java.lang.AssertionError: Status 
Expected :200
Actual   :404
7
Avec 27 Ноя 2016 в 18:58

2 ответа

Лучший ответ

Судя по аннотациям @Path и @GET, вы используете JAX-RS, а не Spring MVC. @WebMvcTest предназначен специально для тестирования веб-фрагмента, реализованного с использованием Spring MVC. Он отфильтровывает компоненты, которые не являются контроллерами Spring MVC, поэтому не будет работать с веб-API, реализованным с использованием JAX-RS.

3
Andy Wilkinson 27 Ноя 2016 в 21:12

Когда я смотрю на ваш класс контроллера, это немного сбивает с толку. Вы используете аннотации @Controller, а затем @Path и @GET, что означает, что вы используете Джерси. Я рекомендую вместо этого использовать @Component. Хотя @Controller расширяет @Component, но все же ....

В любом случае, вы должны использовать org.springframework.boot.test.web.client.TestRestTemplate для тестирования ваших ресурсов отдыха. Например

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootApplicationTests {


    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    public void contextLoads() {
        final ResponseEntity<Health> entity = this.restTemplate.getForEntity("/health", Health.class);
        assertThat(entity.getStatusCode()).isEqualTo(OK);
    }

}

Это должно работать для вас.

Я добавляю pom.xml, который показывает, какие зависимости вам нужно добавить в свой 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>

    <groupId>no.hassan.bones</groupId>
    <artifactId>spring-boot-backbone</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>spring-boot-exmaple-jersey-mvc</name>
    <description>Doing Spring Boot with jersey and spring web-mvc</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jersey</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>               
            </plugin>
        </plugins>
    </build>


</project>

Как видите, я использую как spring mvc, то есть spring-boot-starter-web, так и jersey spring-boot-starter-jersey. Помните, что вам нужно добавить класс @Configuration, который регистрирует ваши конечные точки отдыха Jerse. Вот образец класса для вас

import javax.ws.rs.ApplicationPath;

import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.context.annotation.Configuration;

/**
 * @author Iftikhar Ul Hassan
 */

@Configuration
@ApplicationPath("/rest")
public class JerseyConfig extends ResourceConfig {

    public JerseyConfig() {
        packages("package.path.where.HealthController.resides");

    }
}

Теперь вы можете обслуживать конечные точки для отдыха на майке под /rest/**

0
Hasasn 29 Ноя 2016 в 12:21