Lokaler Einheitentest für Java 8

Mit Einheitentests können Sie die Qualität Ihres Codes überprüfen, nachdem Sie ihn geschrieben haben. Sie können mit diesen Tests aber auch Ihren Entwicklungsprozess verbessern. Anstatt die Tests nach der Entwicklung der Anwendung zu schreiben, sollten Sie sie besser währenddessen schreiben. So können Sie kleine, wartbare, wiederverwendbare Codeeinheiten entwickeln. Außerdem können Sie Ihren Code dadurch sorgfältiger und schneller testen.

Lokale Einheitentests führen Sie in Ihrer eigenen Entwicklungsumgebung und ohne Einbeziehung von Remote-Komponenten aus. App Engine stellt Testdienstprogramme bereit, die lokale Implementierungen von Datastore und anderen App Engine-Diensten verwenden. Mithilfe von Dienst-Stubs können Sie lokal testen, wie Ihr Code diese Dienste nutzt, ohne den Code in App Engine bereitzustellen.

Ein Dienst-Stub ist eine Methode, die das Verhalten des Diensts simuliert. Mit dem Datenspeicherdienst-Stub, der unter Datenspeicher- und Memcache-Tests schreiben dargestellt wird, können Sie beispielsweise Ihren Datenspeichercode testen, ohne dass Anfragen an den realen Datenspeicher gesendet werden. Eine Entität, die während eines Datenspeicher-Einheitentests gespeichert wird, verbleibt im Arbeitsspeicher, nicht im Datenspeicher, und wird im Anschluss an den Test gelöscht. Sie können kurze, schnelle Tests ohne Abhängigkeit vom Datenspeicher selbst ausführen.

Dieses Dokument enthält einige Informationen zum Einrichten eines Test-Frameworks und beschreibt dann, wie Einheitentests für mehrere lokale App Engine-Dienste geschrieben werden.

Test-Framework einrichten

Auch wenn die Testfunktionen des SDK nicht an ein bestimmtes Framework gebunden sind, wird für die Beispiele in diesem Leitfaden JUnit verwendet, sodass Sie ein konkretes und komplettes Framework zum Arbeiten haben. Bevor Sie mit dem Schreiben von Tests beginnen, müssen Sie das entsprechende JUnit 4 JAR zu Ihrem Testklassenpfad hinzufügen. Danach können Sie einen sehr einfachen JUnit-Test schreiben.


import static org.junit.Assert.assertEquals;

import org.junit.Test;

public class MyFirstTest {
  @Test
  public void testAddition() {
    assertEquals(4, 2 + 2);
  }
}

Wenn Sie Eclipse verwenden, müssen Sie die Quelldatei des auszuführenden Tests auswählen. Wählen Sie das Menü Ausführen > Ausführen als > JUnit-Test aus. Die Ergebnisse des Tests werden im Konsolenfenster angezeigt.

Einführung in die Java 8-Testfunktionen

MyFirstTest zeigt die einfachste mögliche Testeinrichtung. Für Tests, die nicht von App Engine-APIs oder lokalen Dienstimplementierungen abhängig sind, benötigen Sie möglicherweise nichts anderes mehr. Wenn jedoch Ihre Tests oder der getestete Code diese Abhängigkeiten haben, fügen Sie Ihrem Testklassenpfad die folgenden JAR-Dateien hinzu:

  • ${SDK_ROOT}/lib/impl/appengine-api.jar
  • ${SDK_ROOT}/lib/impl/appengine-api-stubs.jar
  • ${SDK_ROOT}/lib/appengine-tools-api.jar

Über diese JAR-Dateien stehen die Laufzeit-APIs und die lokalen Implementierungen dieser APIs für Ihre Tests zur Verfügung.

App Engine-Dienste erwarten eine Reihe von Voraussetzungen von ihrer Ausführungsumgebung und das Einrichten dieser Voraussetzungen erfordert recht viel Standardcode. Sie müssen diese Voraussetzungen nicht selbst einrichten, sondern können die Funktionen im com.google.appengine.tools.development.testing-Paket verwenden. Fügen Sie Ihrem Testklassenpfad die folgende JAR-Datei hinzu, um dieses Paket zu verwenden:

  • ${SDK_ROOT}/lib/testing/appengine-testing.jar

Suchen Sie in Javadoc nach dem Paket com.google.appengine.tools.development.testing. Die wichtigste Klasse in diesem Paket ist LocalServiceTestHelper, die alle erforderlichen Umgebungseinstellungen verarbeitet und Ihnen einen Konfigurationspunkt auf oberster Ebene für alle lokalen Dienste bietet, auf die Sie in Ihren Tests möglicherweise zugreifen möchten.

So schreiben Sie einen Test, der auf einen bestimmten lokalen Dienst zugreift:

  • Erstellen Sie eine Instanz von LocalServiceTestHelper mit einer LocalServiceTestConfig-Implementierung für diesen speziellen lokalen Dienst.
  • Rufen Sie vor jedem Test setUp() und nach jedem Test tearDown() für Ihre LocalServiceTestHelper-Instanz auf.

Datenspeicher- und Memcache-Tests schreiben

Im folgenden Beispiel wird die Verwendung des Datenspeicherdiensts getestet.


import static com.google.appengine.api.datastore.FetchOptions.Builder.withLimit;
import static org.junit.Assert.assertEquals;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class LocalDatastoreTest {

  private final LocalServiceTestHelper helper =
      new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());

  @Before
  public void setUp() {
    helper.setUp();
  }

  @After
  public void tearDown() {
    helper.tearDown();
  }

  // Run this test twice to prove we're not leaking any state across tests.
  private void doTest() {
    DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
    assertEquals(0, ds.prepare(new Query("yam")).countEntities(withLimit(10)));
    ds.put(new Entity("yam"));
    ds.put(new Entity("yam"));
    assertEquals(2, ds.prepare(new Query("yam")).countEntities(withLimit(10)));
  }

  @Test
  public void testInsert1() {
    doTest();
  }

  @Test
  public void testInsert2() {
    doTest();
  }
}

In diesem Beispiel sorgt LocalServiceTestHelper für das Einrichten und Entfernen der Teile der Ausführungsumgebung, die allen lokalen Diensten gemeinsam sind, und LocalDatastoreServiceTestConfig sorgt für das Einrichten und Entfernen der Teile der Ausführungsumgebung, die für den lokalen Datenspeicherdienst spezifisch sind. In Javadoc wird beschrieben, dass der lokale Datenspeicherdienst so konfiguriert wird, dass alle Daten im Arbeitsspeicher verbleiben (und nicht in regelmäßigen Abständen auf das Laufwerk geleert werden), und alle In-Memory-Daten am Ende jedes Tests gelöscht werden. Hierbei handelt es sich um das Standardverhalten für einen Datenspeichertest. Ändern Sie dieses Verhalten, wenn es nicht Ihren Vorstellungen entspricht.

Änderung des Beispiels zum Zugreifen auf den Memcache anstelle des Datenspeichers

Zum Erstellen eines Tests, bei dem auf den lokalen Memcache-Dienst zugegriffen wird, verwenden Sie den unten dargestellten Code mit einigen kleinen Änderungen.

Anstatt mit dem Datenspeicher verbundene Klassen zu importieren, importieren Sie Klassen, die mit dem Memcache verbunden sind. Es ist dennoch erforderlich, dass Sie LocalServiceTestHelper importieren.

Ändern Sie den Namen der Klasse, die Sie erstellen, und ändern Sie die LocalServiceTestHelper-Instanz von so, dass sie für den Memcache spezifisch sind.

public class LocalMemcacheTest {

  private final LocalServiceTestHelper helper =
      new LocalServiceTestHelper(new LocalMemcacheServiceTestConfig());

Und ändern Sie schließlich die Art, in der Sie den Test durchführen, damit er für den Memcache relevant ist.

private void doTest() {
  MemcacheService ms = MemcacheServiceFactory.getMemcacheService();
  assertFalse(ms.contains("yar"));
  ms.put("yar", "foo");
  assertTrue(ms.contains("yar"));
}

Wie im Beispiel des Datenspeichers wird die Ausführungsumgebung von LocalServiceTestHelper und der dienstspezifischen LocalServiceTestConfig (in diesem Fall LocalMemcacheServiceTestConfig) verwaltet.

Cloud Datastore-Tests schreiben

Wenn Ihre Anwendung Cloud Datastore verwendet, können Sie Tests schreiben, mit denen das Verhalten Ihrer Anwendung im Hinblick auf Eventual Consistency überprüft wird. Von LocalDatastoreServiceTestConfig werden Optionen bereitgestellt, die dies vereinfachen:


import static com.google.appengine.api.datastore.FetchOptions.Builder.withLimit;
import static org.junit.Assert.assertEquals;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class LocalHighRepDatastoreTest {

  // Maximum eventual consistency.
  private final LocalServiceTestHelper helper =
      new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig()
          .setDefaultHighRepJobPolicyUnappliedJobPercentage(100));

  @Before
  public void setUp() {
    helper.setUp();
  }

  @After
  public void tearDown() {
    helper.tearDown();
  }

  @Test
  public void testEventuallyConsistentGlobalQueryResult() {
    DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
    Key ancestor = KeyFactory.createKey("foo", 3);
    ds.put(new Entity("yam", ancestor));
    ds.put(new Entity("yam", ancestor));
    // Global query doesn't see the data.
    assertEquals(0, ds.prepare(new Query("yam")).countEntities(withLimit(10)));
    // Ancestor query does see the data.
    assertEquals(2, ds.prepare(new Query("yam", ancestor)).countEntities(withLimit(10)));
  }
}

Durch Festlegen des Prozentsatzes nicht angewendeter Jobs auf 100 wird der lokale Datenspeicher angewiesen, die maximale Menge der Eventual Consistency zu nutzen. Maximale Eventual Consistency bedeutet, dass für Schreibvorgänge ein Commit ausgeführt wird, aber bei ihrer Anwendung ein Fehler auftritt. Aus diesem Grund erfolgen für globale Suchanfragen (ohne übergeordnetes Element) niemals Änderungen. Dies ist natürlich nicht repräsentativ für die Menge der Eventual Consistency, die bei Ihrer Anwendung während der Ausführung in der Produktion auftritt. Aber zu Testzwecken ist es sehr hilfreich, den lokalen Datenspeicher so konfigurieren zu können, dass er sich jedes Mal so verhält.

Wenn Sie eine genauere Kontrolle darüber haben möchten, welche Transaktionen nicht zutreffen, können Sie Ihre eigene HighRepJobPolicy registrieren:


import static com.google.appengine.api.datastore.FetchOptions.Builder.withLimit;
import static org.junit.Assert.assertEquals;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.dev.HighRepJobPolicy;
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class LocalCustomPolicyHighRepDatastoreTest {
  private static final class CustomHighRepJobPolicy implements HighRepJobPolicy {
    static int newJobCounter = 0;
    static int existingJobCounter = 0;

    @Override
    public boolean shouldApplyNewJob(Key entityGroup) {
      // Every other new job fails to apply.
      return newJobCounter++ % 2 == 0;
    }

    @Override
    public boolean shouldRollForwardExistingJob(Key entityGroup) {
      // Every other existing job fails to apply.
      return existingJobCounter++ % 2 == 0;
    }
  }

  private final LocalServiceTestHelper helper =
      new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig()
          .setAlternateHighRepJobPolicyClass(CustomHighRepJobPolicy.class));

  @Before
  public void setUp() {
    helper.setUp();
  }

  @After
  public void tearDown() {
    helper.tearDown();
  }

  @Test
  public void testEventuallyConsistentGlobalQueryResult() {
    DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
    ds.put(new Entity("yam")); // applies
    ds.put(new Entity("yam")); // does not apply
    // First global query only sees the first Entity.
    assertEquals(1, ds.prepare(new Query("yam")).countEntities(withLimit(10)));
    // Second global query sees both Entities because we "groom" (attempt to
    // apply unapplied jobs) after every query.
    assertEquals(2, ds.prepare(new Query("yam")).countEntities(withLimit(10)));
  }
}

Mithilfe der Test-APIs können Sie überprüfen, ob sich Ihre Anwendung in Bezug auf Eventual Consistency ordnungsgemäß verhält. Beachten Sie jedoch, dass das lokale High Replication-Lesekonsistenzmodell eine Annäherung an das in der Produktion verwendete High Replication-Lesekonsistenzmodell und kein genaues Replikat ist. In der lokalen Umgebung führt die Ausführung von get() für Entity, die zu einer Entitätengruppe mit einem nicht angewendeten Schreibvorgang gehört, immer dazu, dass die Ergebnisse des nicht angewendeten Schreibvorgangs für nachfolgende globale Abfragen sichtbar werden. In der Produktion ist dies nicht der Fall.

Aufgabenwarteschlangen-Tests schreiben

Tests, die die lokale Aufgabenwarteschlange verwenden, sind etwas komplizierter, da hier im Gegensatz zu Datenspeicher und Memcache die Task Queue API keine Möglichkeit zur Untersuchung des Dienststatus bietet. Wir müssen auf die lokale Aufgabenwarteschlange selbst zugreifen, um zu prüfen, ob eine Aufgabe mit den erwarteten Parametern geplant wurde. Dazu wird com.google.appengine.api.taskqueue.dev.LocalTaskQueue benötigt.


import static org.junit.Assert.assertEquals;

import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.taskqueue.TaskOptions;
import com.google.appengine.api.taskqueue.dev.LocalTaskQueue;
import com.google.appengine.api.taskqueue.dev.QueueStateInfo;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import com.google.appengine.tools.development.testing.LocalTaskQueueTestConfig;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class TaskQueueTest {

  private final LocalServiceTestHelper helper =
      new LocalServiceTestHelper(new LocalTaskQueueTestConfig());

  @Before
  public void setUp() {
    helper.setUp();
  }

  @After
  public void tearDown() {
    helper.tearDown();
  }

  // Run this test twice to demonstrate we're not leaking state across tests.
  // If we _are_ leaking state across tests we'll get an exception on the
  // second test because there will already be a task with the given name.
  private void doTest() throws InterruptedException {
    QueueFactory.getDefaultQueue().add(TaskOptions.Builder.withTaskName("task29"));
    // Give the task time to execute if tasks are actually enabled (which they
    // aren't, but that's part of the test).
    Thread.sleep(1000);
    LocalTaskQueue ltq = LocalTaskQueueTestConfig.getLocalTaskQueue();
    QueueStateInfo qsi = ltq.getQueueStateInfo().get(QueueFactory.getDefaultQueue().getQueueName());
    assertEquals(1, qsi.getTaskInfo().size());
    assertEquals("task29", qsi.getTaskInfo().get(0).getTaskName());
  }

  @Test
  public void testTaskGetsScheduled1() throws InterruptedException {
    doTest();
  }

  @Test
  public void testTaskGetsScheduled2() throws InterruptedException {
    doTest();
  }
}

Beachten Sie, wie wir von LocalTaskqueueTestConfig ein Handle der lokalen Dienstinstanz anfordern und anschließend selbst den lokalen Dienst auf die ordnungsgemäße Planung der Aufgabe hin überprüfen. Alle LocalServiceTestConfig-Implementierungen weisen eine ähnliche Methode auf. Sie werden sie nicht immer brauchen, aber früher oder später werden Sie froh sein, dass es sie gibt.

Konfigurationsdatei queue.xml festlegen

Die Aufgabenwarteschlangen-Testbibliotheken ermöglichen auf einer Pro-LocalServiceTestHelper-Basis die Angabe einer beliebigen Anzahl von queue.xml-Konfigurationen mithilfe der Methode LocalTaskQueueTestConfig.setQueueXmlPath. Derzeit werden die Einstellungen für die Ratenbegrenzung einer Warteschlange vom lokalen Entwicklungsserver ignoriert. Es ist nicht möglich, simultane Aufgaben gleichzeitig lokal auszuführen.

Beispiel: Ein Projekt muss möglicherweise mit der Datei queue.xml getestet werden, die von der App Engine-Anwendung hochgeladen und verwendet wird. Angenommen, die Datei queue.xml befindet sich am Standardspeicherort. In diesem Fall könnte der obige Beispielcode wie folgt geändert werden, um Testzugriff auf die Warteschlangen in der Datei src/main/webapp/WEB-INF/queue.xml zu gewähren:

private final LocalServiceTestHelper helper =
    new LocalServiceTestHelper(new LocalTaskQueueTestConfig()
        .setQueueXmlPath("src/main/webapp/WEB-INF/queue.xml"));

Passen Sie den Pfad zur queue.xml-Datei an die Dateistruktur Ihres Projekts an.

Verwenden Sie die Methode QueueFactory.getQueue, um auf Warteschlangen nach Namen zuzugreifen:

QueueFactory.getQueue("my-queue-name").add(TaskOptions.Builder.withTaskName("task29"));

Tests für zurückgestellte Aufgaben schreiben

Wenn Ihr Anwendungscode zurückgestellte Aufgaben verwendet, erleichtern die Java-Testfunktionen das Schreiben eines Integrationstests, der die Ergebnisse dieser Aufgaben überprüft.


import static org.junit.Assert.assertTrue;

import com.google.appengine.api.taskqueue.DeferredTask;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.taskqueue.TaskOptions;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import com.google.appengine.tools.development.testing.LocalTaskQueueTestConfig;
import java.util.concurrent.TimeUnit;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class DeferredTaskTest {

  // Unlike CountDownLatch, TaskCountDownlatch lets us reset.
  private final LocalTaskQueueTestConfig.TaskCountDownLatch latch =
      new LocalTaskQueueTestConfig.TaskCountDownLatch(1);

  private final LocalServiceTestHelper helper =
      new LocalServiceTestHelper(new LocalTaskQueueTestConfig()
          .setDisableAutoTaskExecution(false)
          .setCallbackClass(LocalTaskQueueTestConfig.DeferredTaskCallback.class)
          .setTaskExecutionLatch(latch));

  private static class MyTask implements DeferredTask {
    private static boolean taskRan = false;

    @Override
    public void run() {
      taskRan = true;
    }
  }

  @Before
  public void setUp() {
    helper.setUp();
  }

  @After
  public void tearDown() {
    MyTask.taskRan = false;
    latch.reset();
    helper.tearDown();
  }

  @Test
  public void testTaskGetsRun() throws InterruptedException {
    QueueFactory.getDefaultQueue().add(
        TaskOptions.Builder.withPayload(new MyTask()));
    assertTrue(latch.await(5, TimeUnit.SECONDS));
    assertTrue(MyTask.taskRan);
  }
}

Wie bei unserem ersten Beispiel einer Warteschlange für lokale Aufgaben verwenden wir LocalTaskqueueTestConfig. Diesmal initialisieren wir sie jedoch mit einigen zusätzlichen Argumenten, die uns ermöglichen, nicht nur zu überprüfen, dass die Aufgabe geplant war, sondern dass die Aufgabe ausgeführt wurde: Wir rufen setDisableAutoTaskExecution(false) auf, damit die Warteschlange für lokale Aufgaben automatisch Aufgaben ausführt. Wir rufen setCallbackClass(LocalTaskQueueTestConfig.DeferredTaskCallback.class) auf, um der Aufgabenwarteschlange mitzuteilen, dass ein Callback verwendet werden soll, das nachvollzieht, wie zurückgestellte Aufgaben ausgeführt werden. Und schließlich rufen wir setTaskExecutionLatch(latch) auf, um der Aufgabenwarteschlange mitzuteilen, dass das Auffangregister nach jeder Aufgabenausführung verringert werden soll. Mit dieser Konfiguration können wir einen Test schreiben, bei dem wir eine zurückgestellte Aufgabe in die Warteschlange stellen, warten, bis diese Aufgabe ausgeführt wird, und dann überprüfen, ob sich die Aufgabe während der Ausführung wie erwartet verhalten hat.

Funktionstests für lokale Dienste schreiben

Funktionstests beinhalten das Ändern des Status eines Diensts, z. B. Datenspeicher, Blobstore, Memcache, und das Ausführen der Anwendung für diesen Dienst. So können Sie prüfen, ob Ihre Anwendung unter verschiedenen Bedingungen erwartungsgemäß reagiert. Der Funktionsstatus kann mithilfe der Klasse LocalCapabilitiesServiceTestConfig geändert werden.

Das folgende Code-Snippet ändert den Funktionsstatus des Datenspeicherdiensts in "deaktiviert" und führt anschließend einen Test für den Datenspeicherdienst aus. Sie können den Datenspeicher nach Bedarf durch andere Dienste ersetzen.


import static org.junit.Assert.assertEquals;

import com.google.appengine.api.capabilities.Capability;
import com.google.appengine.api.capabilities.CapabilityStatus;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.tools.development.testing.LocalCapabilitiesServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import com.google.apphosting.api.ApiProxy;
import org.junit.After;
import org.junit.Test;

public class ShortTest {
  private LocalServiceTestHelper helper;

  @After
  public void tearDown() {
    helper.tearDown();
  }

  @Test(expected = ApiProxy.CapabilityDisabledException.class)
  public void testDisabledDatastore() {
    Capability testOne = new Capability("datastore_v3");
    CapabilityStatus testStatus = CapabilityStatus.DISABLED;
    // Initialize the test configuration.
    LocalCapabilitiesServiceTestConfig config =
        new LocalCapabilitiesServiceTestConfig().setCapabilityStatus(testOne, testStatus);
    helper = new LocalServiceTestHelper(config);
    helper.setUp();
    FetchOptions fo = FetchOptions.Builder.withLimit(10);
    DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
    assertEquals(0, ds.prepare(new Query("yam")).countEntities(fo));
  }
}

Der Beispieltest erstellt zuerst ein Capability-Objekt, das für den Datenspeicher initialisiert wird, und erstellt dann ein CapabilityStatus-Objekt, das auf DISABLED gesetzt ist. Die LocalCapabilitiesServiceTestConfig wird erstellt, wobei die Funktion und der Status mithilfe der gerade erstellten Objekte Capability und CapabilityStatus festgelegt werden.

LocalServiceHelper wird dann mit dem Objekt LocalCapabilitiesServiceTestConfig erstellt. Nun, da der Test eingerichtet wurde, wird DatastoreService erstellt und eine Abfrage gesendet, um festzustellen, ob der Test die erwarteten Ergebnisse generiert, in diesem Fall ein CapabilityDisabledException.

Tests für andere Dienste schreiben

Die Testfunktionen sind für Blobstore und andere App Engine-Dienste verfügbar. Eine Liste aller Dienste mit lokalen Implementierungen für Tests finden Sie in der Dokumentation zu LocalServiceTestConfig.

Tests mit Authentifizierungsvorgaben schreiben

In diesem Beispiel wird gezeigt, wie Sie Tests zum Überprüfen der Logik schreiben, die UserService verwendet, um festzustellen, ob ein Nutzer angemeldet ist oder über Administratorberechtigungen verfügt. Beachten Sie, dass jeder Nutzer mit der einfachen Rolle "Betrachter", "Bearbeiter" oder "Inhaber" oder der vordefinierten Rolle "App Engine-Anwendungsadministrator" über Administratorberechtigungen verfügt.


import static org.junit.Assert.assertTrue;

import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import com.google.appengine.tools.development.testing.LocalUserServiceTestConfig;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class AuthenticationTest {

  private final LocalServiceTestHelper helper =
      new LocalServiceTestHelper(new LocalUserServiceTestConfig())
          .setEnvIsAdmin(true).setEnvIsLoggedIn(true);

  @Before
  public void setUp() {
    helper.setUp();
  }

  @After
  public void tearDown() {
    helper.tearDown();
  }

  @Test
  public void testIsAdmin() {
    UserService userService = UserServiceFactory.getUserService();
    assertTrue(userService.isUserAdmin());
  }
}

In diesem Beispiel konfigurieren wir den LocalServiceTestHelper mit LocalUserServiceTestConfig, damit wir den UserService in unserem Test verwenden können. Wir konfigurieren jedoch auch einige authentifizierungsbezogene Umgebungsdaten auf dem LocalServiceTestHelper selbst.

In diesem Beispiel konfigurieren wir den LocalServiceTestHelper mit dem LocalUserServiceTestConfig damit wir OAuthService verwenden können.