Frage Integrationstests für Google App Engine (Java)


Ich versuche, einige effektive Integrationstests für meine GAE / j-Anwendung zu entwickeln. Ich bin vertraut mit https://developers.google.com/appengine/docs/java/tools/localunittesting - Diese Tools eignen sich hervorragend für kleine Gerätetests. Ich bin jetzt daran interessiert, Integrationstests zu entwickeln, die tatsächliche Webanforderungen testen. Ich möchte beispielsweise testen, dass web.xml Servlets und Filter den erwarteten URLs zuordnet und testet, dass meine JSPs das erzeugen, was ich erwarte.

Mein Ziel war es, innerhalb der JVM einen lokalen Entwicklungsserver aufzustellen, gegen den ich Anfragen richten konnte. Ich bin jedoch offen für andere Integrationsstrategien. Wie ich oben gesagt habe, möchte ich nur die JSP-Generierung und andere Funktionen auf Anfrageebene effektiv testen.

Ich habe DevAppServerFactory verwendet, um einen Entwicklungsserver in derselben JVM zu starten. Es scheint jedoch, dass der erzeugte DevAppServer einen separaten Klassenlader von der Haupt-JVM verwendet. Das macht das Testen sehr viel schwieriger - ich kann keines der lokalen Unittests von Local * TestConfig-Klassen verwenden, um das Verhalten dieses Servers zu kontrollieren. In ähnlicher Weise kann ich nicht meine eigenen Haken zum Modifizieren des Verhaltens über z.B. Statik, da die Statik, die ich im Testkabel mutieren kann, nicht die gleiche Statik ist wie der DevAppServer. Dies macht es schwierig, Merkmale zu überspringen, die für den aktuellen Test nicht zentral sind (z. B. Anmeldung erforderlich), Fehler zu injizieren, Mocks zu injizieren usw. Dies begrenzt wirklich, wie vollständig und effizient ich meinen Code testen kann.

Ich habe einen Mangel an Dokumentation im Web für Integrationstests mit App Engine festgestellt. Ich bin mir sicher, dass jemand das schon einmal gemacht hat ... Gibt es irgendwelche Tipps oder Ressourcen, die du teilen kannst?


10
2017-07-31 15:41


Ursprung


Antworten:


Grundsätzlich müssen Sie zwei Dinge tun:

  1. Füge zwei Servlets hinzu (oder was auch immer), das muss nur während des Tests aktiviert werden, mit denen Sie remote Setup und Teardown auf dem Helper aufrufen können.
  2. Veranlassen Sie, dass Ihre Servlet-Engine Anfragen in einem ausführt vollständig Single-Thread-Art. Dies ist erforderlich, da die von Google bereitgestellte Helper-Klasse aus irgendeinem Grund nur im aktuellen Thread wirksam wird.

2
2017-09-06 09:59



Ich stimme zu, dass dieses Problem schlecht dokumentiert ist.
Ich habe es geschafft, einen Ende-zu-Ende-Test zu schreiben, der einen Server als Blackbox startet und HTTP-Anfragen sendet.

Es funktioniert so:

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

Nun das Problem, das ich habe, ist, dass, wenn Sie zwei dieser Tests haben, mit jeder einzeln passieren, können Sie sie nicht in der gleichen Binärdatei ausführen. Die Ausnahme in Zeile 37 von Diese Datei geworfen werden:

IllegalStateException ("Dev Appserver wird bereits ausgeführt.")

Ich bin mir nicht sicher, wie ich das beheben kann.


0
2018-04-12 12:21