Как провести в памяти юнит-тест Spring-Jersey
Я работаю с Spring-Jersey3 и не могу понять, как выполнить модульное тестирование RESTFul API с бобами Spring
контроллер
package com.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.service.DataSource;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("test")
@Component
public class SpringController {
@Autowired
private DataSource datasource;
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getHello() {
return new String(datasource.load());
}
}
Сервисный интерфейс
package com.service;
public interface DataSource {
public String load();
}
Внедрение сервиса
package com.service;
import org.springframework.stereotype.Repository;
@Repository
public class DataSourceImpl implements DataSource {
@Override
public String load() {
return "Hello";
}
}
ResourceRegister.java (реестр ресурсов Джерси)
package com.component;
import org.glassfish.jersey.server.ResourceConfig;
import com.controller.SpringController;
public class ResourceRegister extends ResourceConfig {
public ResourceRegister () {
register(SpringController.class);
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<servlet>
<servlet-name>Jersey</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.component.ResourceRegister</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
serviceContext.xml (контекст приложения)
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.service" />
<context:component-scan base-package="com.controller" />
</beans>
Модульный тест << - я действительно не знаю, как это проверить
public class test extends JerseyTest {
public test() {
super("com.service", "com.controller");
}
@Override
protected AppDescriptor configure() {
return new WebAppDescriptor.Builder("com.service","com.controller")
.contextParam("contextConfigLocation", "classpath:serviceContext.xml")
.contextPath("/rest")
.servletClass("org.glassfish.jersey.servlet.ServletContainer.class")
.initParam("javax.ws.rs.Application", "com.component.ResourceRegister")
.build();
}
@Test
public void test() {
Client client = new Client();
WebResource resource = client.resource("test");
ClientResponse response = resource.post(ClientResponse.class);
assertEquals(200, resposne.getStatus());
}
}
Исходный код проекта
Проблема: внедрение зависимостей возвращает ноль
1 ответ
Несколько вещей, которые я бы исправил:
Вы используете Jersey 1.x со структурой Jersey Test Framework, но ваше приложение - Jersey 2.x. Смотрите ниже для 2.x зависимости.
Я никогда не использовал тестовую среду Jersey 1.x, но в Jersey 2.x контейнер In-Memory не поддерживает функции, зависящие от сервлетов. Смотрите ниже для другой зависимости.
С Jersey Test Framework вам не нужно создавать
Client
сам. Существует один созданный, и мы можем просто позвонитьJerseyTest
"starget(String path)
способ вернутьWebTarget
(Джерси 2.х,WebResource
это Джерси 1.x)
Вот рефакторинг, который работает.
Зависимость (я только добавил эту зависимость и ничего не убрал, так как ваш проект GitHub не включал в себя ничего связанного с тестом, как в вашем примере кода выше)
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>2.15</version>
</dependency>
Тестовое задание
import com.component.ResourceRegister;
import org.glassfish.jersey.servlet.ServletContainer;
import org.glassfish.jersey.test.DeploymentContext;
import org.glassfish.jersey.test.JerseyTest;
import org.glassfish.jersey.test.ServletDeploymentContext;
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
import org.glassfish.jersey.test.spi.TestContainerFactory;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.web.context.ContextLoaderListener;
public class SpringTest extends JerseyTest {
@Override
protected TestContainerFactory getTestContainerFactory() {
return new GrizzlyWebTestContainerFactory();
}
@Override
protected DeploymentContext configureDeployment(){
return ServletDeploymentContext
.forServlet(new ServletContainer(new ResourceRegister()))
.addListener(ContextLoaderListener.class)
.contextParam("contextConfigLocation", "classpath:applicationContext.xml")
.build();
}
@Test
public void test() {
String response = target("test").request().get(String.class);
Assert.assertEquals("Hello", response);
System.out.println(response);
}
}
Для тех, кто не использует файл контекста xml, вы можете использовать контекст приложения конфигурации аннотации и добавить его в качестве параметра инициализации
return ServletDeploymentContext
.forServlet(new ServletContainer(new ResourceRegister()))
.addListener(ContextLoaderListener.class)
.initParam("contextConfig", new AnnotationConfigApplicationContext(YourSpringConfig.class))
.build();
Другие источники:
- Документация по структуре теста на Джерси
- Дополнительные примеры из тестов исходного кода Test Framework. (Подсказка: ссылка, которую я предоставил, предназначена для примеров гризли веб-контейнера, но если вы вернетесь к поставщикам, вы можете посмотреть на каждого поставщика и перейти к тестовым пакетам для примеров для этих поставщиков)
ОБНОВИТЬ
Итак, после еще нескольких испытаний, вот пара интересных вещей, которые я обнаружил
Один:
С учетом вышеуказанной зависимости, даже если мы не настроим DeploymentContext
и просто переопределить Application configure()
в JerseyTest
, это все еще будет работать. Не могу объяснить это, но кажется, дескриптор все еще поднят.
import javax.ws.rs.core.Application;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Assert;
import org.junit.Test;
public class SpringTest extends JerseyTest {
@Override
public Application configure() {
return new ResourceConfig().packages("com.controller");
}
@Test
public void test() {
String response = target("test").request().get(String.class);
Assert.assertEquals("Hello", response);
System.out.println(response);
}
}
Два:
Даже если мы избавимся от вышеуказанной зависимости (гризли) и используем зависимость в памяти, этот же простой предыдущий тест будет работать. Документация гласит
Контейнер In-Memory не является реальным контейнером. Он запускает приложение в Джерси и напрямую вызывает внутренние API-интерфейсы для обработки запроса, созданного клиентом, предоставляемым тестовой средой. Нет сетевого взаимодействия. Эти контейнеры не поддерживают сервлет и другие зависимые от контейнера функции, но это идеальный выбор для простых модульных тестов.
Поэтому я не совсем уверен, на какие функции сервлета они ссылаются, так как этот тест все еще работает
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-inmemory</artifactId>
<version>2.15</version>
</dependency>
Что я не понимаю, в частности, это утверждение
"Нет связи с сетью"
потому что когда я запускаю тест, я вижу журнал
INFO: Creating InMemoryTestContainer configured at the base URI http://localhost:9998/