#java #spring #integration-testing #jersey-2.0 #jersey-test-framework
#java #spring #интеграция-тестирование #джерси-2.0 #jersey-test-framework
Вопрос:
У меня есть веб-сервисы Джерси, которые используют spring для внедрения зависимостей (модуль spring-jersey) и спящий режим для объектно-реляционного отображения (ORM). Для разработки интеграционных тестов с учетом следующих условий:
- Запустите тестовый контейнер только один раз для всего тестового класса
- Зарегистрируйте пользовательские прослушиватели, фильтры, сервлеты и т. Д. В тестовом контейнере
- Убедитесь, что @Context HttpServletRequest не равен null
В соответствии с этим https://java.net/jira/browse/JERSEY-2412 Jersey project JIRA task HttpServletRequest имеет значение null, и это, как показано в разрешении задачи, работает так, как определено. При запуске интеграционных тестов в контейнере Grizzly он запускает интеграционные тесты на http-сервере, следовательно, любая зависимость от функций на основе сервлетов, таких как HttpServletRequest, HttpServletResponse и т. Д., недоступна.
Похоже, нет стандартного решения о том, как решить эту проблему, и сообщество Джерси, очевидно, открыто для таких функций, разрабатываемых участниками, как указано в этом https://java.net/jira/browse/JERSEY-2417 Билет JIRA. Каковы возможные обходные решения, пока эта функция не будет реализована? Основываясь на моих исследованиях, я натыкаюсь на несколько сообщений, в которых говорится:
- Используйте внешний контейнер (что, если я тоже не хочу?)
- Используйте модуль jetty от jersey (что, если я не хочу использовать Jetty?)
- Решения, специфичные для SpringMVC, которые не применяются к этому проекту (поскольку мы не используем Spring MVC)
Итак, каково наилучшее решение для успешного запуска интеграционных тестов на веб-серверах на основе джерси, которые используют мост spring-jersey для внедрения зависимостей и полагаются на функции на основе сервлетов?
Ответ №1:
Это стандартное поведение Джерси, и разрешить функции на основе сервлетов, такие как HttpServletRequest, пока недоступно. Основываясь на моих исследованиях, я мог бы выполнить следующие условия
- Запустите тестовый контейнер только один раз для всего тестового класса
- Зарегистрируйте пользовательские прослушиватели, фильтры, сервлеты и т. Д. В тестовом контейнере
- Убедитесь, что @Context HttpServletRequest не равен null
Путем запуска / остановки контейнера grizzly вручную и развертывания экземпляра контейнера grizzly в пользовательском WebAppContext на основе джерси. На случай, если кто-нибудь еще столкнется с такой проблемой, выполните следующие действия
- Создайте HTTPServer
- В @Before создайте пользовательский WebAppContext, который отражает ваш web.xml и разверните свой экземпляр HTTPServer с помощью WebAppContext
- Чтобы убедиться, что функции на основе сервлетов, такие как HttpServletRequest, доступны во время интеграционного теста, используйте ServletRegistration для загрузки вашего приложения в контейнер сервлета, как показано ниже
Шаг #1
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:applicationContext.xml" })
public class ResourceEndpointIntegrationTest{
@Context
private HttpServletRequest httpReq;
private static Logger logger = Logger.getLogger(ResourceEndpointIntegrationTest.class);
public static final String BASE_URI = "http://localhost:8989/";
private static HttpServer server = null;
@BeforeClass
public static void initTest() {
RestAssured.baseURI = "http://localhost:8989/";
}
...
}
Использовать SpringJUnit4ClassRunner.class и @ContextConfiguration для загрузки applicationContext.xml для проведения тестов. Также объявите @Context HttpServletRequest и создайте
экземпляр HTTPServer для последующего использования. Я использую @BeforeClass здесь для определенных целей (вам не обязательно его использовать), это необязательно.
Шаг #2
@Before
public void setup() throws Exception {
if (server == null) {
System.out.println("Initializing an instance of Grizzly Container ...");
final ResourceConfig rc = new ResourceConfig(ResourceEndpointIntegrationTest.class, ..., ..., ...); //update
WebappContext ctx = new WebappContext("IntegrationTestContext");
//register your listeners from web.xml in here
ctx.addListener("com.xxx.yyy.XEndpointServletContextListener");
//register your applicationContext.xml here
ctx.addContextInitParameter("contextConfigLocation", "classpath:applicationContext.xml");
//ServletRegistration is needed to load the ResourceConfig rc inside ServletContainer or you will have no
//Servlet-based features available
ServletRegistration registration = ctx.addServlet("ServletContainer",
new ServletContainer(rc));
//Initialize the Grizzly server passing it base URL
server = GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI));
//Deploy the server using our custom context
ctx.deploy(server);
}
}
Настройка в @Before выполняется для каждого теста, но условие if заставит метод setup действовать как @BeforeClass, позволяя нам инициализировать
сервер один раз для всего тестового класса за вычетом статического характера @BeforeClass .
Причина, по которой я инициализирую сервер один раз для всех тестов внутри тестового класса, заключается в том, что, если мы этого не сделаем, у нас будет следующий рабочий процесс
- Запущен сервер
- Spring запускает сканирование на наличие компонентов
- Spring автоматически подключается
- Spring настраивает SessionFactory и т. Д.
- Тест запущен
- Spring разрушает контекст
- Сервер завершает работу
- Повторите шаги с # 1 по # 7 для каждого теста
Вышеизложенное занимает очень много времени и технически невозможно, поэтому инициализируйте контейнер один раз (именно поэтому я не расширяю JerseyTest, потому что я хочу контролировать запуск / завершение работы тестового контейнера).
#Шаг 3
@AfterClass
public static void tearDown() throws Exception {
System.out.println("Integration tests completed. Tear down the server ...");
if (server != null amp;amp; server.isStarted()) {
server.shutdownNow();
System.out.println("Grizzly instance shutdown completed");
}
}
На шаге 3 мы используем @AfterClass для завершения работы экземпляра grizzly, используемого для целей тестирования интеграции.
И пример теста выглядит следующим образом
@Test
public void testCreateSomethingReturnSuccessfully() {
JSONObject something = new JSONObject();
cust.put("name", "integrationTest");
cust.put("age", 33);
given().
contentType(ContentType.JSON).
body(something.toString()).post("/someEndpoint").
then().
statusCode(200).
assertThat().
body("id", greaterThan(0)).
body("name", equalTo("integrationTest")).
body("age", equalTo(33));
}
(Gradle) Некоторые из соответствующих зависимостей
compile group: 'org.glassfish.jersey.containers', name: 'jersey-container-servlet', version: '2.23.2'
compile group: 'org.glassfish.jersey.test-framework.providers', name:'jersey-test-framework-provider-grizzly2', version:'2.23.2'
compile group: 'org.springframework', name:'spring-test', version:'4.3.2.RELEASE'
compile group: 'io.rest-assured', name:'rest-assured', version:'3.0.1'
// Spring
compile group: 'org.springframework', name: 'spring-core', version: '4.3.2.RELEASE'
compile group: 'org.springframework', name: 'spring-beans', version: '4.3.2.RELEASE'
compile group: 'org.springframework', name: 'spring-web', version: '4.3.2.RELEASE'
compile group: 'org.springframework', name: 'spring-jdbc', version: '4.3.2.RELEASE'
compile group: 'org.springframework', name: 'spring-orm', version: '4.3.2.RELEASE'
// Jersey-Spring bridge
compile (group: 'org.glassfish.jersey.ext', name: 'jersey-spring3', version: '2.23.2'){
exclude group: 'org.springframework', module: 'spring-core'
exclude group: 'org.springframework', module: 'spring-web'
exclude group: 'org.springframework', module: 'spring-beans'
exclude group: 'org.springframework', module: 'spring-jdbc'
exclude group: 'org.springframework', module: 'spring-orm'
}
Некоторые импортные
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.Context;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.grizzly.servlet.ServletRegistration;
import org.glassfish.grizzly.servlet.WebappContext;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletContainer;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;