Test unitaire Android Studio: lire le fichier de données (entrée)

96

Dans un test unitaire, comment puis-je lire des données à partir d'un fichier json sur mon système de fichiers (de bureau), sans coder en dur le chemin?

Je voudrais lire l'entrée de test (pour mes méthodes d'analyse) à partir d'un fichier au lieu de créer des chaînes statiques.

Le fichier se trouve au même emplacement que mon code de test unitaire, mais je peux également le placer ailleurs dans le projet si nécessaire. J'utilise Android Studio.

Franc
la source
3
J'ai essayé presque toutes les combinaisons avec IOUtils.toString (this.getClass (). GetResourceAsStream ("test_documents.json"), "UTF-8"), il renvoie toujours null. Probablement parce que les fichiers ne seront pas inclus dans le fichier jar.
Frank
Parlons-nous de tests unitaires impliquant un émulateur / appareil Android?
AndroidEx
@ Android777 Je pense que nous parlons de la nouvelle prise en charge des tests unitaires introduite dans la version récente d'Android Studio tools.android.com/tech-docs/unit-testing-support
akhy
@Frank où placez-vous test_documents.json? répertoire des actifs?
akhy
Oui, nous parlons du nouveau support des tests unitaires, n'impliquant pas l'émulateur / l'appareil. Je ne l'ai pas placé dans le répertoire assets, car il est ensuite emballé avec l'apk live. Je l'ai placé dans le même dossier que les fichiers de test (java).
Frank

Réponses:

149

Selon la android-gradle-pluginversion:

1. version 1.5 et supérieure:

Mettez simplement le fichier json src/test/resources/test.jsonet référencez-le comme

classLoader.getResource("test.json"). 

Aucune modification de gradle n'est nécessaire.

2. version inférieure à 1.5 : (ou si pour une raison quelconque la solution ci-dessus ne fonctionne pas)

  1. Assurez-vous que vous utilisez au moins Android Gradle Plugin version 1.1 . Suivez le lien pour configurer correctement Android Studio.

  2. Créer un testrépertoire. Placez les classes de test unitaire dans le javarépertoire et placez votre fichier de ressources dans le resrépertoire. Android Studio doit les marquer comme suit:

    entrez la description de l'image ici

  3. Créez une gradletâche pour copier les ressources dans le répertoire des classes pour les rendre visibles pour classloader:

    android{
       ...
    }
    
    task copyResDirectoryToClasses(type: Copy){
        from "${projectDir}/src/test/res"
        into "${buildDir}/intermediates/classes/test/debug/res"
    }
    
    assembleDebug.dependsOn(copyResDirectoryToClasses)
  4. Vous pouvez maintenant utiliser cette méthode pour obtenir une Fileréférence pour la ressource de fichier:

    private static File getFileFromPath(Object obj, String fileName) {
        ClassLoader classLoader = obj.getClass().getClassLoader();
        URL resource = classLoader.getResource(fileName);
        return new File(resource.getPath());
    }
    
    @Test
    public void fileObjectShouldNotBeNull() throws Exception {
        File file = getFileFromPath(this, "res/test.json");
        assertThat(file, notNullValue());
    }
  5. Exécutez le test unitaire par Ctrl+ Shift+ F10sur toute la classe ou sur une méthode de test spécifique.
Klimat
la source
1
Impressionnant! Votre montage, sans tests instrumentaux, fonctionne comme un charme, merci!
Frank
4
C'est une bonne solution, mais cela ne fonctionne pas toujours. Si vous exécutez la tâche de nettoyage, puis exécutez testDebug, cela échoue. Fondamentalement, le développeur doit savoir qu'il doit exécuter la tâche assembleDebug avant testDebug. Avez-vous des suggestions pour améliorer cela?
joaoprudencio
18
Avec AndroidStudio 1.5 avec le plugin android 1.5.0 placez votre fichier json ici src/test/resources/test.jsonet référencez-le comme classLoader.getResource("test.json"). Aucune modification de gradle n'est nécessaire. Les dossiers imbriqués à l'intérieur resourcesfonctionnent également.
Sergii Pechenizkyi
6
Réponse incomplète. Qu'est-ce que c'est classLoader? où placer cette ligne de code? que pouvez-vous faire avec le résultat de retour ?. Veuillez fournir un code plus complet. -1
voghDev
3
A lire ./src/test/resources/file.txtà Kotlin:TestClassName::class.java.getResource("/file.txt")!!.readText()
Erik
76

Pour les tests unitaires locaux (par rapport aux tests d'instrumentation), vous pouvez placer des fichiers sous src/test/resourceset les lire à l'aide de classLoader. Par exemple, le code suivant ouvre le myFile.txtfichier dans le répertoire des ressources.

InputStream in = this.getClass().getClassLoader().getResourceAsStream("myFile.txt");

Cela a fonctionné avec

  • Android Studio 1.5.1
  • plugin gradle 1.3.1
user3113045
la source
Cela ne fonctionne pas pour moi s'il vous plaît voir ma question ici stackoverflow.com/questions/36295824/…
Tyler Pfaff
5
Cela a fonctionné pour moi, quand je suis passé de "src / test / res" à "src / test / resources". En utilisant Android Studio 2.0 RC 3, gradle: 2.0.0-rc3
Alex Bravo
a fonctionné comme prévu. Mais le test est réussi même si le fichier n'est pas disponible sous "src / test / resources /" par exemple: "rules.xml", mais InputStream a pour résultat nul dans ce cas.
anand krish
4
kotlin:val myFile = ClassLoader.getSystemResource("myFile.txt").readText()
jj.
A travaillé comme du charme!
Amit Bhandari
15

Dans mon cas, la solution était d'ajouter au fichier gradle

sourceSets {
    test.resources.srcDirs += 'src/unitTests/resources'
  } 

Après cela, tout a été trouvé par AS 2.3.1

javaClass.classLoader.getResourceAsStream("countries.txt")
ar-g
la source
1
J'ai fait quelque chose de très similaire (Kotlin): 1. créer un dossier et un fichier à: root/app/src/test/resources/test.json 2. lire des données comme ceci:val jsonFile = ClassLoader.getSystemResource("test.json").readText()
jj.
8

J'ai eu beaucoup de problèmes avec les ressources de test dans Android Studio, j'ai donc mis en place quelques tests pour plus de clarté. Dans mon projet mobile(Application Android), j'ai ajouté les fichiers suivants:

mobile/src/test/java/test/ResourceTest.java
mobile/src/test/resources/test.txt
mobile/src/test/resources/test/samePackage.txt

La classe de test (tous les tests réussissent):

assertTrue(getClass().getResource("test.txt") == null);
assertTrue(getClass().getResource("/test.txt").getPath().endsWith("test.txt"));
assertTrue(getClass().getResource("samePackage.txt").getPath().endsWith("test/samePackage.txt"));
assertTrue(getClass().getResource("/test/samePackage.txt").getPath().endsWith("test/samePackage.txt"));
assertTrue(getClass().getClassLoader().getResource("test.txt").getPath().endsWith("test.txt"));
assertTrue(getClass().getClassLoader().getResource("test/samePackage.txt").getPath().endsWith("test/samePackage.txt"));

Dans le même projet racine, j'ai un projet Java (pas Android) appelé data. Si j'ajoute les mêmes fichiers au projet de données:

data/src/test/java/test/ResourceTest.java
data/src/test/resources/test.txt
data/src/test/resources/test/samePackage.txt

Ensuite, tous les tests ci-dessus échoueront si je les exécute depuis Android Studio, mais ils passent sur la ligne de commande avec ./gradlew data:test. Pour contourner cela, j'utilise ce hack (dans Groovy)

def resource(String path) {
    getClass().getResource(path) ?:
            // Hack to load test resources when executing tests from Android Studio
            new File(getClass().getClassLoader().getResource('.').path
                    .replace('/build/classes/test/', "/build/resources/test$path"))
}

Usage: resource('/test.txt')

Android Studio 2.3, Gradle 3.3

L'amour
la source
Excellente réponse (après 45 minutes de recherche 😌). Il va au cœur de plusieurs problèmes et facilite la réplication des résultats à l'aide des tests eux-mêmes. Fwiw, dans AS 2.3.1, Gradle 2.3.1, les getClassLoader()versions fonctionnent comme prévu. C'est-à-dire qu'ils trouvent les fichiers, tous deux exécutés à partir d'Android Studio ET de la ligne de commande sur ma machine macOS et sur le serveur Linux CI (CircleCI). Donc je vais avec ça et j'espère que Gradle 3.3 ne le cassera pas plus tard ...
mm2001
Agréable! Je vois le même problème de chargement des ressources ici. AS 2.3.2, Gradle 3.3. Les tests fonctionnent à partir de la ligne de commande mais pas via AS, car ils build/resources/testne sont pas inclus dans le chemin de classe interactif.
Mark McKenna
6

Si vous allez dans Exécuter -> Modifier les configurations -> JUnit puis sélectionnez la configuration d'exécution pour vos tests unitaires, il existe un paramètre «Répertoire de travail». Cela devrait indiquer où se trouve votre fichier json. Gardez à l'esprit que cela pourrait casser d'autres tests.

Tas Morf
la source
et que d'utiliser this.getClass (). getResourceAsStream (test.json)? J'ai ajouté les fichiers là-bas, à la racine du projet, il ne trouve toujours pas les fichiers.
Frank
Cela peut être utilisé pour charger des fichiers en utilisant new File()ou similaire, mais cela ne fonctionne pas directement avec la méthode de chargement de chemin de classe décrite ci-dessus. C'est aussi un peu délicat car chaque nouvelle configuration d'exécution doit définir le répertoire de travail, et par défaut la ligne de commande AS et Gradle aiment utiliser différents répertoires de travail ... une telle douleur
Mark McKenna
4

Je pensais que je devrais ajouter mes conclusions ici. Je sais que c'est un peu vieux mais pour les nouvelles versions de Gradle, où il n'y a PAS de répertoire src / test / resources, mais un seul répertoire de ressources pour l'ensemble du projet, vous devez ajouter cette ligne à votre fichier Gradle.

android {
   testOptions {
      unitTests {
         includeAndroidResources = true
      }
    }
}

En faisant cela, vous pouvez accéder à votre ressource avec:

 this.getClass().getClassLoader().getResourceAsStream(fileName);

J'ai cherché ceci et je n'ai pas trouvé de réponse, alors j'ai décidé d'aider les autres ici.

Raphael Ayres
la source
1

En fait, c'est ce qui a fonctionné pour moi avec les tests d'instrumentation (exécutant Android Studio version 3.5.3 , Android Gradle Plugin version 3.5.3 , Gradle version 6.0.1 ):

  1. Mettez vos fichiers dans un src/androidTest/assetsdossier
  2. Dans votre fichier de test:

InputStream is = InstrumentationRegistry.getInstrumentation().getContext().getAssets().open("filename.txt");

Michele
la source