Lokale Einheitentests erstellen

Ein lokaler Test wird direkt auf Ihrer eigenen Workstation ausgeführt und nicht auf einem Android-Gerät oder Emulator. Daher wird zum Ausführen von Tests Ihre lokale Java Virtual Machine (JVM) und nicht ein Android-Gerät verwendet. Mit lokalen Tests lässt sich die Logik Ihrer App schneller auswerten. Wenn Sie jedoch nicht mit dem Android-Framework interagieren können, schränken Sie die Arten der Tests ein, die Sie ausführen können.

Mit einem Einheitentest wird das Verhalten eines kleinen Codeabschnitts, der zu testenden Einheit, überprüft. Dazu wird dieser Code ausgeführt und das Ergebnis überprüft.

Einheitentests sind in der Regel einfach, ihre Einrichtung kann jedoch problematisch sein, wenn die zu testende Einheit nicht im Hinblick auf die Testbarkeit entwickelt wurde:

  • Der Code, den Sie bestätigen möchten, muss in einem Test zugänglich sein. Sie können eine private Methode beispielsweise nicht direkt testen. Stattdessen testen Sie die Klasse mit ihren öffentlichen APIs.
  • Damit Einheitentests isoliert ausgeführt werden, müssen die Abhängigkeiten der zu testenden Einheit durch von Ihnen gesteuerte Komponenten ersetzt werden, z. B. Fälschungen oder andere Test-Doubles. Dies ist besonders problematisch, wenn Ihr Code vom Android-Framework abhängt.

Informationen zu gängigen Strategien für Einheitentests in Android finden Sie unter Zu testende Elemente.

Standort für lokale Tests

Standardmäßig werden die Quelldateien für lokale Einheitentests in module-name/src/test/ gespeichert. Dieses Verzeichnis ist bereits vorhanden, wenn Sie ein neues Projekt mit Android Studio erstellen.

Testabhängigkeiten hinzufügen

Außerdem müssen Sie die Testabhängigkeiten für Ihr Projekt so konfigurieren, dass die vom JUnit-Test-Framework bereitgestellten Standard-APIs verwendet werden.

Öffnen Sie dazu die Datei build.gradle Ihrer Anwendung und geben Sie die folgenden Bibliotheken als Abhängigkeiten an. Geben Sie mit der Funktion testImplementation an, dass sie für die lokale Testquelle und nicht für die Anwendung gelten:

dependencies {
  // Required -- JUnit 4 framework
  testImplementation "junit:junit:$jUnitVersion"
  // Optional -- Robolectric environment
  testImplementation "androidx.test:core:$androidXTestVersion"
  // Optional -- Mockito framework
  testImplementation "org.mockito:mockito-core:$mockitoVersion"
  // Optional -- mockito-kotlin
  testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion"
  // Optional -- Mockk framework
  testImplementation "io.mockk:mockk:$mockkVersion"
}

Lokale Einheitentestklasse erstellen

Sie schreiben Ihre lokale Unittest-Klasse als JUnit 4-Testklasse.

Erstellen Sie dazu eine Klasse, die eine oder mehrere Testmethoden enthält, normalerweise in module-name/src/test/. Eine Testmethode beginnt mit der Annotation @Test und enthält den Code, der ausgeführt und ein einzelner Aspekt der zu testenden Komponente geprüft wird.

Das folgende Beispiel zeigt, wie eine lokale Einheitentestklasse implementiert wird. Mit der Testmethode emailValidator_correctEmailSimple_returnsTrue()wird versucht, die Methode isValidEmail() zu überprüfen, da es sich um eine Methode innerhalb der App handelt. Die Testfunktion gibt „true“ zurück, wenn isValidEmail() ebenfalls „true“ zurückgibt.

Kotlin


import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test

class EmailValidatorTest {
  @Test fun emailValidator_CorrectEmailSimple_ReturnsTrue() {
    assertTrue(EmailValidator.isValidEmail("name@email.com"))
  }

}

Java


import org.junit.Test;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

class EmailValidatorTest {
  @Test
  public void emailValidator_CorrectEmailSimple_ReturnsTrue() {
    assertTrue(EmailValidator.isValidEmail("name@email.com"));
  }
}

Sie sollten lesbare Tests erstellen, die bewerten, ob die Komponenten in Ihrer Anwendung die erwarteten Ergebnisse zurückgeben. Wir empfehlen die Verwendung einer Assertion-Bibliothek wie junit.Assert, Hamcrest oder Truth. Das obige Snippet ist ein Beispiel für die Verwendung von junit.Assert.

Mockable Android-Bibliothek

Wenn Sie lokale Einheitentests ausführen, enthält das Android Gradle-Plug-in eine Bibliothek, die alle APIs des Android-Frameworks enthält, und zwar in der jeweils in Ihrem Projekt verwendeten Version. Die Bibliothek enthält alle öffentlichen Methoden und Klassen dieser APIs. Der Code innerhalb der Methoden wurde jedoch entfernt. Wenn auf eine der Methoden zugegriffen wird, gibt der Test eine Ausnahme aus.

Dadurch können lokale Tests erstellt werden, wenn auf Klassen im Android-Framework wie Context verwiesen wird. Und was noch wichtiger ist: Sie können ein Mocking-Framework mit Android-Klassen verwenden.

Mocking von Android-Abhängigkeiten

Ein typisches Problem besteht darin, herauszufinden, ob eine Klasse eine String-Ressource verwendet. Sie können Stringressourcen abrufen, indem Sie die Methode getString() in der Klasse Context aufrufen. Ein lokaler Test kann jedoch weder Context noch eine der zugehörigen Methoden verwenden, da sie zum Android-Framework gehören. Idealerweise wird der Aufruf von getString() aus der Klasse entfernt. Das ist jedoch nicht immer praktisch. Die Lösung besteht darin, einen Mock oder einen Stub von Context zu erstellen, der immer denselben Wert zurückgibt, wenn die Methode getString() aufgerufen wird.

Mit der Mockable Android-Bibliothek und Mocking-Frameworks wie Mockito oder MockK können Sie das Verhalten von Modellen der Android-Klassen in Ihren Einheitentests programmieren.

Wenn Sie Ihrem lokalen Einheitentest mit Mockito ein simuliertes Objekt hinzufügen möchten, folgen Sie diesem Programmiermodell:

  1. Fügen Sie die Abhängigkeit der Mockito-Bibliothek in die Datei build.gradle ein, wie unter Testumgebung einrichten beschrieben.
  2. Fügen Sie am Anfang der Unittest-Klassendefinition die Annotation @RunWith(MockitoJUnitRunner.class) hinzu. Diese Annotation weist den Mockito-Test-Runner an, zu validieren, dass Sie das Framework korrekt verwendet haben, und vereinfacht die Initialisierung Ihrer Mock-Objekte.
  3. Wenn Sie ein Mock-Objekt für eine Android-Abhängigkeit erstellen möchten, fügen Sie vor der Felddeklaration die Annotation @Mock hinzu.
  4. Mit den Methoden when() und thenReturn() können Sie eine Bedingung und einen Rückgabewert angeben, wenn die Bedingung erfüllt ist.

Das folgende Beispiel zeigt, wie Sie einen Einheitentest erstellen, der ein Context-Beispielobjekt in Kotlin verwendet, das mit Mockito-Kotlin erstellt wurde.

import android.content.Context
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.junit.MockitoJUnitRunner
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock

private const val FAKE_STRING = "HELLO WORLD"

@RunWith(MockitoJUnitRunner::class)
class MockedContextTest {

  @Mock
  private lateinit var mockContext: Context

  @Test
  fun readStringFromContext_LocalizedString() {
    // Given a mocked Context injected into the object under test...
    val mockContext = mock<Context> {
        on { getString(R.string.name_label) } doReturn FAKE_STRING
    }

    val myObjectUnderTest = ClassUnderTest(mockContext)

    // ...when the string is returned from the object under test...
    val result: String = myObjectUnderTest.getName()

    // ...then the result should be the expected one.
    assertEquals(result, FAKE_STRING)
  }
}

Weitere Informationen zur Verwendung des Mockito-Frameworks finden Sie in der Referenz zur Mockito API und in der Klasse SharedPreferencesHelperTest im Beispielcode. Sehen Sie sich auch das Android Testing Codelab an.

Fehler: „Method ... not mocked“

Die Mockable Android-Bibliothek gibt eine Ausnahme aus, wenn Sie versuchen, mit der Nachricht Error: "Method ... not mocked auf eine ihrer Methoden zuzugreifen.

Wenn die ausgegebenen Ausnahmen für Ihre Tests problematisch sind, können Sie das Verhalten so ändern, dass die Methoden je nach Rückgabetyp stattdessen entweder null oder null zurückgeben. Fügen Sie dazu die folgende Konfiguration in der obersten build.gradle-Datei Ihres Projekts in Groovy ein:

android {
  ...
  testOptions {
    unitTests.returnDefaultValues = true
  }