Test lokalny działa bezpośrednio na Twojej stacji roboczej, a nie na urządzeniu z Androidem czy emulatorze. W związku z tym do testów jest wykorzystywana lokalna maszyna wirtualna Java (JVM), a nie urządzenie z Androidem. Testy lokalne umożliwiają szybsze ocenę logiki aplikacji. Jednak brak możliwości interakcji z platformą Android ogranicza liczbę dostępnych testów.
Test jednostkowy pozwala sprawdzić zachowanie niewielkiej części kodu – testowej jednostki. Aby to zrobić, uruchamia odpowiedni kod i sprawdza wynik.
Testy jednostkowe są zwykle proste, ale ich konfiguracja może sprawiać problemy, jeśli jednostka w trakcie testów nie została zaprojektowana pod kątem możliwości testowania:
- Kod, który chcesz zweryfikować, musi być dostępny z poziomu testu. Na przykład nie można bezpośrednio testować metody prywatnej. Zamiast tego przetestujesz klasę przy użyciu publicznych interfejsów API.
- Aby testy jednostkowe były przeprowadzane w izolacji, zależności jednostki w testach muszą zostać zastąpione komponentami, które kontrolujesz, takimi jak fałszywe lub inne meble podwójne. Problem dotyczy szczególnie tych, które są zależne od platformy Androida.
Aby dowiedzieć się więcej o typowych strategiach testowania jednostkowego na Androidzie, przeczytaj artykuł Co przetestować.
Lokalizacja testów lokalnych
Domyślnie pliki źródłowe dla testów jednostkowych znajdują się w regionie module-name/src/test/
. Katalog ten jest już utworzony podczas
tworzenia nowego projektu w Android Studio.
Dodawanie zależności testowych
Musisz też skonfigurować zależności testowe w projekcie, aby używać standardowych interfejsów API udostępnianych przez platformę testów JUnit.
Aby to zrobić, otwórz plik build.gradle
modułu aplikacji i określ następujące biblioteki jako zależności. Użyj funkcji testImplementation
, aby wskazać, że dotyczą one lokalnego zbioru źródłowego, a nie aplikacji:
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"
}
Tworzenie klasy testowej jednostki lokalnej
Zapisujesz klasę testową jednostki lokalnej jako klasę testową JUnit 4.
Aby to zrobić, utwórz klasę zawierającą co najmniej 1 metodę testowania, zwykle w obiekcie module-name/src/test/
. Metoda testowania zaczyna się od adnotacji @Test
i zawiera kod do ćwiczenia i weryfikacji jednego aspektu komponentu, który chcesz przetestować.
Przykład poniżej pokazuje, jak wdrożyć klasę testową jednostki lokalnej. Metoda testowa emailValidator_correctEmailSimple_returnsTrue()
próbuje zweryfikować metodę isValidEmail()
, która jest metodą stosowaną w aplikacji. Funkcja testowa zwróci wartość „true” (prawda), jeśli isValidEmail()
również zwróci wartość „true” (prawda).
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")); } }
Należy utworzyć czytelne testy, które oceniają, czy komponenty aplikacji zwracają oczekiwane wyniki. Zalecamy korzystanie z biblioteki asercji, takiej jak junit.Assert, Hamcrest lub Truth. Powyższy fragment kodu to przykład użycia właściwości junit.Assert
.
Pozorowana biblioteka Androida
Gdy przeprowadzasz testy jednostkowe, wtyczka Androida do obsługi Gradle zawiera bibliotekę, która zawiera wszystkie interfejsy API platformy Androida zgodne z wersją używaną w Twoim projekcie. W bibliotece znajdują się wszystkie metody i klasy publiczne tych interfejsów API, ale kod wewnątrz metod został usunięty. Jeśli dostępna jest któraś z metod, test zgłasza wyjątek.
Dzięki temu można tworzyć testy lokalne, odwołując się do klas w platformie Androida, takiej jak Context
. Co ważne, w klasach Androida
można wykorzystać model do żartów.
Imitowanie zależności Androida
Typowym problemem jest zauważenie, że klasa korzysta z zasobu tekstowego. Zasoby z ciągami znaków możesz uzyskać, wywołując metodę getString()
w klasie Context
. W teście lokalnym nie można jednak używać metody Context
ani żadnej z jej metod, ponieważ należą one do platformy Androida. W idealnej sytuacji wywołanie getString()
zostałoby usunięte z zajęć, ale nie zawsze jest to praktyczne. Rozwiązaniem jest utworzenie symulowanego interfejsu Context
, który zawsze zwraca tę samą wartość po wywołaniu metody getString()
.
Dzięki bibliotece mockable Android i platformom do żartów, takim jak Mockito czy MockK, możesz zaprogramować w testach jednostkowych działanie próbek klas Androida.
Aby za pomocą Mockito dodać przykładowy obiekt do testu jednostki lokalnej, postępuj zgodnie z tym modelem programowania:
- Dodaj zależność z biblioteki Mockito do pliku
build.gradle
zgodnie z opisem w sekcji Konfigurowanie środowiska testowego. - Na początku definicji klasy testu jednostkowego dodaj adnotację
@RunWith(MockitoJUnitRunner.class)
. Ta adnotacja informuje usługę uruchamiającą testy Mockito, aby sprawdzić, czy użycie platformy jest poprawne, i upraszcza inicjowanie obiektów próbnych. - Aby utworzyć pozorowany obiekt dla zależności Androida, dodaj adnotację
@Mock
przed deklaracją pola. - Aby skrócić zachowanie zależności, możesz określić warunek i zwrócić wartość w przypadku jego spełnienia, korzystając z metod
when()
ithenReturn()
.
W poniższym przykładzie pokazano, jak utworzyć test jednostkowy, który wykorzystuje w kotlinie próbny obiekt Context
utworzony za pomocą metody Mockito-Kotlin.
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)
}
}
Więcej informacji o korzystaniu z platformy Mockito znajdziesz w materiałach referencyjnych Mockito API i klasie SharedPreferencesHelperTest
w przykładowym kodzie. Wypróbuj też ćwiczenia z programowania dotyczące testowania aplikacji na Androida.
Błąd: „Metoda ... to nie jest przykładowa”
Biblioteka Pozorna Androida zgłasza wyjątek, jeśli próbujesz uzyskać dostęp do którejkolwiek z jej metod za pomocą komunikatu Error: "Method ... not mocked
.
Jeśli zgłoszone wyjątki stanowią problem dla testów, możesz zmienić działanie, tak aby metody zwracały wartość null lub zero w zależności od typu zwrotu. Aby to zrobić, dodaj tę konfigurację do pliku build.gradle
najwyższego poziomu w Groovy:
android {
...
testOptions {
unitTests.returnDefaultValues = true
}