Crea test delle unità locali

Un test locale viene eseguito direttamente sulla tua workstation, anziché su un dispositivo Android dispositivo o emulatore. Di conseguenza, utilizza la tua Java Virtual Machine (JVM) locale, piuttosto che un dispositivo Android, per eseguire i test. I test locali consentono di valutare della logica dell'app. Tuttavia, la mancata interazione con i Il framework Android crea un limite nei tipi di test che puoi eseguire.

Un test di unità verifica il comportamento di una piccola sezione di codice, l'unità in esame. A tal fine, esegue il codice e controlla il risultato.

I test di unità sono in genere semplici, ma la loro configurazione può essere problematica quando l'unità in esame non è progettata tenendo conto della testabilità:

  • Il codice che vuoi verificare deve essere accessibile da un test. Ad esempio, non puoi testare direttamente un metodo privato. Devi invece testare la classe utilizzando le sue API pubbliche.
  • Per eseguire i test delle unità in isolamento, le dipendenze dell'unità in esame devono essere sostituite da componenti che controlli, ad esempio falsi o altri doppini di test. Questo è particolarmente problematico se il codice dipende dal framework Android.

Per scoprire le strategie più comuni per i test delle unità in Android, leggi l'articolo Cosa test.

Località dei test locali

Per impostazione predefinita, i file di origine per i test delle unità locali vengono inseriti module-name/src/test/. Questa directory esiste già quando ne crei una nuova utilizzando Android Studio.

Aggiunta di dipendenze di test

Devi anche configurare le dipendenze di test per il tuo progetto in modo che utilizzi le API standard fornite dal framework di test JUnit.

Per farlo, apri il file build.gradle del modulo dell'app e specifica le seguenti librerie come dipendenze. Utilizza la funzione testImplementation per indicare che si applicano al set di origini test locale e non all'applicazione:

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

Crea una classe di test delle unità locali

Scrivi la classe di test delle unità locale come classe di test JUnit 4.

Per farlo, crea una classe contenente uno o più metodi di test, di solito in module-name/src/test/. Un metodo di test inizia con l'annotazione @Test e contiene il codice per verificare e testare un singolo aspetto del componente che vuoi testare.

Il seguente esempio mostra come implementare una classe di test unitario locale. Il metodo di test emailValidator_correctEmailSimple_returnsTrue()tenta di verificareisValidEmail(), che è un metodo all'interno dell'app. La funzione di test restituirà true se anche isValidEmail() restituisce true.

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

Devi creare test leggibili per valutare se i componenti nel tuo restituiscono i risultati previsti. Ti consigliamo di usare una libreria di asserzioni come come junit.Assert, Hamcrest o Verità. Lo snippet riportato sopra è un esempio di come utilizzare junit.Assert.

Libreria Android simulabile

Quando esegui i test delle unità locali, il plug-in Android per Gradle include una contenente tutte le API del framework Android, corretta nel utilizzata nel progetto. La biblioteca contiene tutti i metodi pubblici e di queste API, ma il codice all'interno dei metodi è stato rimosso. Se presente dei metodi a cui si accede, il test genera un'eccezione.

In questo modo è possibile creare test locali quando si fa riferimento a classi nel framework Android come Context. Ma soprattutto, consente di usare un modello con le classi di Android.

Simulazione delle dipendenze di Android

Un problema tipico consiste nel scoprire che una classe utilizza una risorsa stringa. Puoi ottenere risorse stringa richiamando il metodo getString() nel metodo Context . Tuttavia, un test locale non può utilizzare Context o uno dei suoi metodi poiché appartengono al framework Android. Idealmente, la chiamata a getString() dovrebbe essere rimossa dal corso, ma non è sempre pratico. La soluzione è creare un mock o uno stub di Context che restituisca sempre lo stesso valore quando viene invocato il suo metodo getString().

Con la libreria Android simulabile e i framework di simulazione come Mockito o MockK, puoi programmare il comportamento dei mock delle classi Android nei tuoi test di unità.

Per aggiungere un oggetto fittizio al test delle unità locali utilizzando Mockito, segui questo modello di programmazione:

  1. Includi la dipendenza dalla libreria Mockito nel file build.gradle, come descritto in Configurare l'ambiente di test.
  2. All'inizio della definizione della classe di test delle unità, aggiungi il metodo Annotazione @RunWith(MockitoJUnitRunner.class). Questa annotazione indica runner di test simulato per verificare che l'utilizzo del framework sia corretto e semplifica l'inizializzazione degli oggetti fittizi.
  3. Per creare un oggetto fittizio per una dipendenza Android, aggiungi l'annotazione @Mock prima della dichiarazione del campo.
  4. Per eseguire lo stub del comportamento della dipendenza, puoi specificare una condizione e un valore di ritorno quando la condizione è soddisfatta utilizzando i metodi when() e thenReturn().

L'esempio seguente mostra come creare un test di unità che utilizza un oggetto mock Context in Kotlin creato con 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)
  }
}

Per scoprire di più sull'utilizzo del framework Mockito, consulta l'articolo sull'API Mockito riferimento e la classe SharedPreferencesHelperTest nel codice campione: Prova anche il codelab di test su Android.

Errore: "Metodo ... non simulato"

La libreria Android simulabile genera un'eccezione se provi ad accedere a uno dei suoi metodi con il messaggio Error: "Method ... not mocked.

Se le eccezioni lanciate sono problematiche per i test, puoi modificare il comportamento in modo che i metodi restituiscano null o zero, a seconda del tipo di ritorno. Per farlo, aggiungi la seguente configurazione nel file build.gradle di primo livello in Groovy:

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