Интеграционные тесты для Google App Engine (java)
Я пытаюсь разработать некоторые эффективные интеграционные тесты для моего приложения GAE/j. Я знаком с https://developers.google.com/appengine/docs/java/tools/localunittesting - эти инструменты отлично подходят для небольших модульных тестов. Теперь я заинтересован в разработке интеграционных тестов, которые проверяют фактические веб-запросы. Например, я хотел бы проверить, что web.xml сопоставляет сервлеты и фильтры с ожидаемыми URL-адресами и проверяет, что мои JSP генерируют то, что я ожидаю.
Моя цель состояла в том, чтобы открыть локальный сервер разработки внутри JVM, от которого я мог бы запускать запросы. Однако я открыт для других стратегий интеграции; как я сказал выше, я просто хочу эффективно тестировать генерацию JSP и другие функции уровня запроса.
Мне удалось использовать DevAppServerFactory для запуска сервера разработки в той же JVM. Однако, похоже, что созданный DevAppServer использует отдельный загрузчик классов от основной JVM. Это делает тестирование намного более сложным - я не могу использовать какие-либо локальные классы Unitesting Local * TestConfig для управления поведением этого сервера. Точно так же я не могу "свернуть свои собственные" крючки для изменения поведения с помощью, например, statics, так как статика, которую я могу мутировать в тестовом жгуте, не является той же статистикой, на которую смотрит DevAppServer. Это делает сложным пропустить функции, не являющиеся центральными для текущего теста (например, для входа в систему), для ввода отказов, для приведения макетов и т.д. Это действительно ограничивает, насколько полностью и эффективно я могу проверить свой код.
Я нашел реальную нехватку документации в Интернете для тестирования интеграции с App Engine. Я уверен, что кто-то сделал это раньше... есть ли какие-либо советы или ресурсы, которые вы можете поделиться?
Ответы
Ответ 1
В принципе, вам нужно сделать две вещи:
- Добавьте два сервлета (или что-то еще), , которые должны быть включены только во время тестирования, что позволяет удаленно вызывать установку и отключение помощника.
- Сделайте ваш сервлет-механизм подачей запросов полностью однопоточным способом. Это необходимо, потому что по какой-то причине класс Helper Google действует только в текущем потоке.
Ответ 2
Я согласен, что этот вопрос плохо документирован.
Мне удалось написать сквозной тест, который запускает сервер как черный ящик и отправляет ему HTTP-запросы.
Он работает следующим образом:
package com.project.org;
import static org.junit.Assert.assertEquals;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import com.google.appengine.api.urlfetch.HTTPResponse;
import com.google.appengine.api.urlfetch.URLFetchServiceFactory;
import com.google.appengine.tools.development.testing.BaseDevAppServerTestConfig;
import com.google.appengine.tools.development.testing.DevAppServerTest;
import com.google.appengine.tools.development.testing.DevAppServerTestRunner;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
@RunWith(DevAppServerTestRunner.class)
@DevAppServerTest(HelloWorldTest.TestConfig.class)
public class HelloWorldTest {
public class TestConfig extends BaseDevAppServerTestConfig {
@Override public File getSdkRoot() {
// You may need to tweak this.
return new File("../../appengine-java-sdk-1.9.15");
}
@Override public File getAppDir() {
return new File("war");
}
@Override
public List<URL> getClasspath() {
// There may be an easier way to do this.
List<URL> classPath = new ArrayList<>();
try {
String separator = System.getProperty("path.separator");
String[] pathElements = System.getProperty("java.class.path").split(separator);
for (String pathElement : pathElements) {
classPath.add(new File(pathElement).toURI().toURL());
}
}
catch (MalformedURLException e) {
throw new RuntimeException(e);
}
return classPath;
}
}
private final LocalServiceTestHelper testHelper;
private final String port;
public HelloWorldTest() {
testHelper = new LocalServiceTestHelper();
port = System.getProperty("appengine.devappserver.test.port");
}
@Before public void setUpServer() {
testHelper.setUp();
}
@After public void tearDown() {
testHelper.tearDown();
}
@Test public void testHelloWorld() throws Exception {
URL url = new URL("http://localhost:" + port + "/hello");
HTTPResponse response = URLFetchServiceFactory.getURLFetchService().fetch(url);
assertEquals(200, response.getResponseCode());
assertEquals("Hello world!", new String(response.getContent(), "UTF-8"));
}
}
Теперь проблема заключается в том, что если у вас есть два теста, каждый из которых проходит отдельно, вы не можете запускать их в одном и том же двоичном файле.
Исключено в строке 37 этот файл:
IllegalStateException ( "Dev Appserver уже запущен".)
Не знаю, как это исправить.