Recherche…


Remarques

Créer des tests unitaires locaux

Placez vos classes de test ici: /src/test/<pkg_name>/

Exemple de classe de test

public class ExampleUnitTest {
    @Test
    public void addition_isCorrect() throws Exception {
        int a=4, b=5, c;
        c = a + b;
        assertEquals(9, c); // This test passes
        assertEquals(10, c); //Test fails
    }
}

Panne

public class ExampleUnitTest {
  ...
}

La classe de test, vous pouvez créer plusieurs classes de test et les placer dans le package de test.

@Test
public void addition_isCorrect() {
   ...
}

La méthode de test, plusieurs méthodes de test peuvent être créées dans une classe de test.

Notez l'annotation @Test .

L'annotation Test indique à JUnit que la méthode vide publique à laquelle elle est attachée peut être exécutée en tant que scénario de test.

Il existe plusieurs autres annotations utiles comme @Before , @After etc. Cette page serait un bon point de départ.

assertEquals(9, c); // This test passes
assertEquals(10, c); //Test fails

Ces méthodes sont membres de la classe Assert . Quelques autres méthodes utiles sont assertFalse() , assertNotNull() , assertTrue etc. Voici une explication détaillée.


Informations d'annotation pour le test JUnit:

@Test: L'annotation Test indique à JUnit que la méthode vide publique à laquelle elle est attachée peut être exécutée en tant que scénario de test. Pour exécuter la méthode, JUnit construit d'abord une nouvelle instance de la classe, puis appelle la méthode annotée.

@Before: Lors de l'écriture des tests, il est courant de constater que plusieurs tests nécessitent des objets similaires créés avant de pouvoir être exécutés. Annoter une méthode vide publique avec @Before provoque l' @Before cette méthode avant la méthode Test.

@Après: Si vous allouez des ressources externes dans une méthode Before, vous devez les libérer après le test. Annoter une méthode vide publique avec @After provoque l' @After cette méthode après la méthode Test. Toutes les méthodes @After sont garanties pour s'exécuter même si une méthode Before ou Test émet une exception


Astuce Créez rapidement des classes de test dans Android Studio

  • Placez le curseur sur le nom de la classe pour laquelle vous souhaitez créer une classe de test.
  • Appuyez sur Alt + Entrée (Windows).
  • Sélectionnez Créer un test, appuyez sur Retour.
  • Sélectionnez les méthodes pour lesquelles vous souhaitez créer des méthodes de test, cliquez sur OK.
  • Sélectionnez le répertoire dans lequel vous souhaitez créer la classe de test.
  • Vous avez terminé, ce que vous obtenez est votre premier test.

Astuce Exécuter facilement des tests dans Android Studio

  • Faites un clic droit pour tester le paquet.
  • Sélectionnez Run 'Tests in ...
  • Tous les tests du package seront exécutés immédiatement.

Déplacement de la logique métier hors des composants Android

Une grande partie de la valeur des tests unitaires JVM locaux provient de la façon dont vous concevez votre application. Vous devez le concevoir de telle sorte que vous puissiez découpler votre logique métier de vos composants Android. Voici un exemple d'utilisation du modèle Model-View-Presenter . Permet de s'exercer en mettant en place un écran d'inscription de base qui ne prend qu'un nom d'utilisateur et un mot de passe. Notre application Android est chargée de valider que le nom d'utilisateur fourni par l'utilisateur n'est pas vide et que le mot de passe comporte au moins huit caractères et au moins un chiffre. Si le nom d'utilisateur / mot de passe est valide, nous effectuons notre appel api d'inscription, sinon nous affichons un message d'erreur.

Exemple où la logique métier est fortement couplée au composant Android.

public class LoginActivity extends Activity{
    ...
    private void onSubmitButtonClicked(){
        String username = findViewById(R.id.username).getText().toString();
        String password = findViewById(R.id.password).getText().toString();
        boolean isUsernameValid = username != null && username.trim().length() != 0;
        boolean isPasswordValid = password != null && password.trim().length() >= 8 && password.matches(".*\\d+.*");
        if(isUsernameValid && isPasswordValid){
            performSignUpApiCall(username, password);
        } else {
            displayInvalidCredentialsErrorMessage();
        }
    }
}

Exemple où la logique métier est découplée du composant Android.

Nous définissons ici dans une seule classe, LoginContract, les différentes interactions entre nos différentes classes.

public interface LoginContract {
    public interface View {
        performSignUpApiCall(String username, String password);
        displayInvalidCredentialsErrorMessage();
    }
    public interface Presenter {
        void validateUserCredentials(String username, String password);
    }
}

Notre LoginActivity est pour la plupart identique, sauf que nous avons supprimé la responsabilité de savoir comment valider le formulaire d'inscription d'un utilisateur (notre logique métier). LoginActivity s'appuiera désormais sur notre nouveau LoginPresenter pour effectuer la validation.

public class LoginActivity extends Activity implements LoginContract.View{
    private LoginContract.Presenter presenter;

    protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            presenter = new LoginPresenter(this);
            ....
        }
        ...

        private void onSubmitButtonClicked(){
            String username = findViewById(R.id.username).getText().toString();
            String password = findViewById(R.id.password).getText().toString();
            presenter.validateUserCredentials(username, password);
    }
    ...
}

Votre logique métier réside désormais dans votre nouvelle classe LoginPresenter.

public class LoginPresenter implements LoginContract.Presenter{
    private LoginContract.View view;

    public LoginPresenter(LoginContract.View view){
        this.view = view;
    }

    public void validateUserCredentials(String username, String password){
        boolean isUsernameValid = username != null && username.trim().length() != 0;
        boolean isPasswordValid = password != null && password.trim().length() >= 8 && password.matches(".*\\d+.*");
        if(isUsernameValid && isPasswordValid){
            view.performSignUpApiCall(username, password);
        } else {
            view.displayInvalidCredentialsErrorMessage();
        }
    }
}

Et maintenant, nous pouvons créer des tests unitaires JVM locaux par rapport à votre nouvelle classe LoginPresenter.

public class LoginPresenterTest {

    @Mock
    LoginContract.View view;

    private LoginPresenter presenter;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        presenter = new LoginPresenter(view);
    }

    @Test
    public void test_validateUserCredentials_userDidNotEnterUsername_displayErrorMessage() throws Exception {
        String username = "";
        String password = "kingslayer1";
        presenter.validateUserCredentials(username, password);
        Mockito.verify(view). displayInvalidCredentialsErrorMessage();
    }

    @Test
    public void test_validateUserCredentials_userEnteredFourLettersAndOneDigitPassword_displayErrorMessage() throws Exception {
        String username = "Jaime Lanninster";
        String password = "king1";
        presenter.validateUserCredentials(username, password);
        Mockito.verify(view). displayInvalidCredentialsErrorMessage();
    }

    @Test
    public void test_validateUserCredentials_userEnteredNineLettersButNoDigitsPassword_displayErrorMessage() throws Exception {
        String username = "Jaime Lanninster";
        String password = "kingslayer";
        presenter.validateUserCredentials(username, password);
        Mockito.verify(view). displayInvalidCredentialsErrorMessage();
    }

    @Test
    public void test_validateUserCredentials_userEnteredNineLettersButOneDigitPassword_performApiCallToSignUpUser() throws Exception {
        String username = "Jaime Lanninster";
        String password = "kingslayer1";
        presenter.validateUserCredentials(username, password);
        Mockito.verify(view).performSignUpApiCall(username, password);
    }
}

Comme vous pouvez le constater, lorsque nous avons extrait notre logique métier de LoginActivity et l’avons placée dans le POJO LoginPresenter. Nous pouvons maintenant créer des tests unitaires JVM locaux en fonction de notre logique métier.

Il convient de noter que notre changement d’architecture a plusieurs autres implications, comme l’adhésion à chaque classe ayant une responsabilité unique, des classes supplémentaires, etc. Ce ne sont que des effets secondaires de la manière dont je choisis découplage via le style MVP. MVP n’est qu’une façon d’y parvenir, mais vous pouvez également envisager d’autres solutions, telles que MVVM . Il vous suffit de choisir le meilleur système qui fonctionne pour vous.

Démarrer avec JUnit

Installer

Pour lancer l'unité de test de votre projet Android à l'aide de JUnit, vous devez ajouter la dépendance JUnit à votre projet et créer un ensemble de sources de test qui contiendra le code source des tests unitaires. Les projets créés avec Android Studio incluent souvent déjà la dépendance JUnit et le jeu de sources de test

Ajoutez la ligne suivante à votre fichier build.gradle module dans les dépendances Closure :

testCompile 'junit:junit:4.12'

Les classes de test JUnit se trouvent dans un ensemble de sources nommé test . Si cet ensemble de sources n'existe pas, vous devez créer un nouveau dossier vous-même. La structure de dossiers d'un projet Android Studio (basé sur Gradle) par défaut ressemble à ceci:

<project-root-folder>
    /app (module root folder)
        /build
        /libs
        /src
            /main (source code)
            /test (unit test source code)
            /androidTest (instrumentation test source code)
        build.gradle (module gradle file)
    /build
    /gradle
    build.gradle (project gradle file)
    gradle.properties
    gradlew
    gradlew.bat
    local.properties
    settings.gradle (gradle settings)

Si votre projet ne dispose pas du dossier /app/src/test , vous devez le créer vous-même. Dans le dossier de test , vous avez également besoin d'un dossier java (créez-le s'il n'existe pas). Le dossier Java dans le jeu de sources de test doit contenir la même structure de package que votre jeu de sources main .

Si la configuration est correcte, la structure de votre projet (dans la vue Android d’Android Studio) devrait ressembler à ceci:

configuration du projet

Remarque: Vous n'avez pas nécessairement besoin du androidTest sources androidTest , cet ensemble de sources se trouve souvent dans les projets créés par Android Studio et est inclus ici pour référence.


Écrire un test

  1. Créez une nouvelle classe dans le jeu de sources de test .
    Cliquez avec le bouton droit de la souris sur le jeu de sources de test dans la vue du projet, choisissez New > Java class .
    Le modèle de nommage le plus utilisé consiste à utiliser le nom de la classe que vous allez tester avec Test ajouté. Donc, StringUtilities devient StringUtilitiesTest .

  2. Ajouter l'annotation @RunWith
    L'annotation @RunWith est nécessaire pour que JUnit exécute les tests que nous allons définir dans notre classe de test. Le runner JUnit par défaut (pour JUnit 4) est le BlockJUnit4ClassRunner mais, au lieu d'utiliser directement cette exécution, il est plus pratique d'utiliser l'alias JUnit4 qui est un raccourci pour le runner JUnit par défaut.

     @RunWith(JUnit4.class)
     public class StringUtilitiesTest {
     
     }
    
  3. Créer un test
    Un test unitaire est essentiellement une méthode qui, dans la plupart des cas, ne doit pas échouer si elle est exécutée. En d'autres termes, il ne devrait pas lancer d'exception. Dans une méthode de test, vous trouverez presque toujours des assertions qui vérifient si des conditions spécifiques sont remplies. Si une assertion échoue, elle génère une exception qui entraîne l'échec de la méthode / du test. Une méthode de test est toujours annotée avec l'annotation @Test . Sans cette annotation, JUnit ne lancera pas automatiquement le test.

     @RunWith(JUnit4.class)
     public class StringUtilitiesTest {
    
         @Test
         public void addition_isCorrect() throws Exception {
             assertEquals("Hello JUnit", "Hello" + " " + "JUnit");
         }
     }
    

    Remarque: contrairement à la méthode Java standard, les noms de méthode de test des unités de convention contiennent souvent des traits de soulignement.


Lancer un test

  1. Méthode
    Pour exécuter une méthode de test unique, vous pouvez cliquer avec le bouton droit sur la méthode et cliquer sur Run 'addition_isCorrect()' ou utiliser le raccourci clavier ctrl+shift+f10 . Exécuter un seul test unitaire

    Si tout est configuré correctement, JUnit commence à exécuter la méthode et vous devriez voir l'interface suivante dans Android Studio:

    Interface de test d'unité Android Studio

  1. Classe
    Vous pouvez également exécuter tous les tests définis dans une seule classe, en cliquant avec le bouton droit sur la classe dans la vue du projet et en cliquant sur Run 'StringUtilitiesTest ' ou utilisez le raccourci clavier ctrl+shift+f10 si vous avez sélectionné la classe dans la vue du projet.

  2. Package (tout)
    Si vous ne voulez pas exécuter tous les tests définis dans le projet ou dans un package, vous pouvez cliquer avec le bouton droit sur le package et cliquer sur Run ... comme si vous exécutiez tous les tests définis dans une seule classe.

Des exceptions

JUnit peut également être utilisé pour tester si une méthode renvoie une exception spécifique pour une entrée donnée.

Dans cet exemple, nous allons tester si la méthode suivante renvoie vraiment une exception si le format booléen (input) n'est pas reconnu / inconnu:

public static boolean parseBoolean(@NonNull String raw) throws IllegalArgumentException{
    raw = raw.toLowerCase().trim();
    switch (raw) {
        case "t": case "yes": case "1": case "true":
            return true;
        case "f": case "no": case "0": case "false":
            return false;
        default:
            throw new IllegalArgumentException("Unknown boolean format: " + raw);
    }
}

En ajoutant le paramètre expected à l'annotation @Test , vous pouvez définir quelle exception est susceptible d'être lancée. Le test unitaire échouera si cette exception ne se produit pas et réussit si l'exception est bien levée:

@Test(expected = IllegalArgumentException.class)
public void parseBoolean_parsesInvalidFormat_throwsException(){
    StringUtilities.parseBoolean("Hello JUnit");
}

Cela fonctionne bien, cependant, cela vous limite à un seul cas de test dans la méthode. Parfois, vous pouvez vouloir tester plusieurs cas dans une même méthode. Une technique souvent utilisée pour surmonter cette limitation consiste à utiliser try-catch blocs try-catch et la méthode Assert.fail() :

@Test
public void parseBoolean_parsesInvalidFormats_throwsException(){
    try {
        StringUtilities.parseBoolean("Hello!");
        fail("Expected IllegalArgumentException");
    } catch(IllegalArgumentException e){
    }

    try {
        StringUtilities.parseBoolean("JUnit!");
        fail("Expected IllegalArgumentException");
    } catch(IllegalArgumentException e){
    }
}

Remarque: certaines personnes considèrent que tester un seul cas à l’intérieur d’un test unitaire est une mauvaise pratique.

Import statique

JUnit définit quelques méthodes assertEquals au moins une pour chaque type de primitive et une autre pour les objets. Ces méthodes ne sont pas directement disponibles par défaut pour être appelées et doivent être appelées comme ceci: Assert.assertEquals . Mais comme ces méthodes sont utilisées, les utilisateurs utilisent souvent une importation statique, de sorte que la méthode peut être utilisée directement comme si elle faisait partie de la classe elle-même.

Pour ajouter une importation statique pour la méthode assertEquals , utilisez l'instruction d'importation suivante:

import static org.junit.Assert.assertEquals;

Vous pouvez également importer de manière statique toutes les méthodes d'assert, y compris assertArrayEquals , assertNotNull et assertFalse utilisant l'importation statique suivante:

import static org.junit.Assert.*;

Sans importation statique:

@Test
public void addition_isCorrect(){
    Assert.assertEquals(4 , 2 + 2);
}

Avec importation statique:

@Test
public void addition_isCorrect(){
    assertEquals(4 , 2 + 2);
}


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow