Teste de unidade do Android Studio: ler arquivo de dados (entrada)

96

Em um teste de unidade, como posso ler dados de um arquivo json em meu sistema de arquivos (desktop), sem codificar o caminho?

Gostaria de ler a entrada de teste (para meus métodos de análise) de um arquivo em vez de criar Strings estáticas.

O arquivo está no mesmo local que meu código de teste de unidade, mas também posso colocá-lo em outro lugar do projeto, se necessário. Estou usando o Android Studio.

Frank
fonte
3
Tentei quase todas as combinações com IOUtils.toString (this.getClass (). GetResourceAsStream ("test_documents.json"), "UTF-8"), ele sempre retorna nulo. Provavelmente porque os arquivos não serão incluídos no jar.
Frank,
Estamos falando de testes de unidade envolvendo emulador / dispositivo Android?
AndroidEx
@ Android777 Acho que estamos falando sobre o novo suporte de teste de unidade introduzido na versão recente do Android Studio tools.android.com/tech-docs/unit-testing-support
akhy
@Frank onde você coloca test_documents.json? diretório de ativos?
akhy
Sim, estamos falando sobre o novo suporte de teste de unidade, não envolvendo o emulador / dispositivo. Eu não coloquei no diretório de ativos, porque então ele é empacotado com o apk ao vivo. Coloquei-o na mesma pasta dos arquivos de teste (java).
Frank

Respostas:

149

Dependendo da android-gradle-pluginversão:

1. versão 1.5 e superior:

Basta colocar o arquivo json src/test/resources/test.jsone referenciá-lo como

classLoader.getResource("test.json"). 

Nenhuma modificação gradle é necessária.

2. versão abaixo de 1.5 : (ou se por algum motivo a solução acima não funcionar)

  1. Certifique-se de usar pelo menos o Android Gradle Plugin versão 1.1 . Siga o link para configurar o Android Studio corretamente.

  2. Crie o testdiretório. Coloque classes de teste de unidade no javadiretório e coloque seu arquivo de recursos no resdiretório. O Android Studio deve marcá-los como segue:

    insira a descrição da imagem aqui

  3. Crie uma gradletarefa para copiar recursos no diretório de classes para torná-los visíveis para classloader:

    android{
       ...
    }
    
    task copyResDirectoryToClasses(type: Copy){
        from "${projectDir}/src/test/res"
        into "${buildDir}/intermediates/classes/test/debug/res"
    }
    
    assembleDebug.dependsOn(copyResDirectoryToClasses)
  4. Agora você pode usar este método para obter Filereferência para o recurso de arquivo:

    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. Execute o teste de unidade Ctrl+ Shift+ F10em toda a classe ou método de teste específico.
klimat
fonte
1
Impressionante! Sua edição, sem instrumentaltests, funciona como um encanto, obrigado!
Frank,
4
É uma boa solução, mas nem sempre funciona. Se você executar, execute a tarefa de limpeza e, em seguida, testDebug, ela falhará. Basicamente, o desenvolvedor precisa saber que deve executar a tarefa assembleDebug antes de testDebug. Vocês têm alguma sugestão para melhorar isso?
joaoprudencio
18
Com o AndroidStudio 1.5 com o plugin do Android 1.5.0 coloque seu arquivo json aqui src/test/resources/test.jsone faça referência a ele como classLoader.getResource("test.json"). Nenhuma modificação gradle é necessária. As pastas aninhadas dentro resourcestambém estão funcionando.
Sergii Pechenizkyi
6
Resposta incompleta. O que é classLoader? onde colocar esta linha de código? o que você pode fazer com o resultado de retorno ?. Forneça um código mais completo. -1
voghDev
3
Para ler ./src/test/resources/file.txtem Kotlin:TestClassName::class.java.getResource("/file.txt")!!.readText()
Erik
76

Para testes de unidade locais (vs. testes de instrumentação), você pode colocar arquivos src/test/resourcese lê-los usando classLoader. Por exemplo, o código a seguir abre o myFile.txtarquivo no diretório de recursos.

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

Funcionou com

  • Android Studio 1.5.1
  • plugin gradle 1.3.1
user3113045
fonte
Isso não está funcionando para mim, veja minha pergunta aqui stackoverflow.com/questions/36295824/…
Tyler Pfaff
5
Isso funcionou para mim, quando mudei de "src / test / res" para "src / test / resources". Usando o Android Studio 2.0 RC 3, gradle: 2.0.0-rc3
Alex Bravo
funcionou como esperado. Mas o teste está sendo aprovado mesmo se o arquivo não estiver disponível em "src / test / resources /", por exemplo: "rules.xml", mas InputStream resulta em nulo neste caso.
anand krish,
4
kotlin:val myFile = ClassLoader.getSystemResource("myFile.txt").readText()
jj.
Funcionou como charme!
Amit Bhandari de
15

No meu caso, a solução foi adicionar ao arquivo gradle

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

Depois disso tudo foi encontrado pelo AS 2.3.1

javaClass.classLoader.getResourceAsStream("countries.txt")
ar-g
fonte
Fiz algo muito semelhante (Kotlin): 1. crie a pasta e o arquivo em: root/app/src/test/resources/test.json 2. leia os dados como este:val jsonFile = ClassLoader.getSystemResource("test.json").readText()
jj.
8

Tive muitos problemas com recursos de teste no Android Studio, então configurei alguns testes para maior clareza. No meu projeto mobile(aplicativo Android), adicionei os seguintes arquivos:

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

A classe de teste (todos os testes são aprovados):

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

No mesmo projeto raiz, tenho um projeto Java (não Android) chamado data. Se eu adicionar os mesmos arquivos ao projeto de dados:

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

Então, todos os testes acima falharão se eu executá-los no Android Studio, mas eles passam na linha de comando com ./gradlew data:test. Para contornar isso, eu uso este hack (em 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"))
}

Uso: resource('/test.txt')

Android Studio 2.3, Gradle 3.3

Ame
fonte
Ótima resposta (após 45 minutos de pesquisa 😌). Ele atinge o cerne de vários problemas e facilita a replicação dos resultados usando os próprios testes. Fwiw, no AS 2.3.1, Gradle 2.3.1, as getClassLoader()versões funcionam conforme o esperado. Ou seja, eles encontram os arquivos, ambos executados no Android Studio E na linha de comando em minha máquina macOS e no servidor Linux CI (CircleCI). Então, vou continuar com isso e espero que o Gradle 3.3 não seja interrompido mais tarde ...
mm2001
Agradável! Estou vendo o mesmo problema de carregamento de recursos aqui. AS 2.3.2, Gradle 3.3. Os testes funcionam a partir da linha de comando, mas não por meio do AS, devido a build/resources/testnão serem incluídos no classpath interativo.
Mark McKenna
6

Se você acessar Executar -> Editar configurações -> JUnit e selecionar a configuração de execução para seus testes de unidade, haverá uma configuração de 'Diretório de trabalho'. Isso deve apontar para onde quer que esteja seu arquivo json. Lembre-se de que isso pode quebrar outros testes.

Tas Morf
fonte
e usar this.getClass (). getResourceAsStream (test.json)? Adicionei os arquivos lá, na raiz do projeto, ainda não encontra os arquivos.
Frank,
Isso pode ser usado para carregar arquivos usando new File()ou semelhante, mas não funciona diretamente com o método de carregamento de caminho de classe descrito acima. Também é um pouco complicado porque cada nova configuração de execução precisa definir o diretório de trabalho e, por padrão, as linhas de comando do AS e do Gradle usam diferentes diretórios de trabalho ... uma dor de cabeça
Mark McKenna
4

Achei que deveria adicionar minhas descobertas aqui. Eu sei que isso é um pouco antigo, mas para as versões mais recentes do Gradle, onde NÃO existe o diretório src / test / resources, mas apenas um único diretório de recursos para todo o projeto, é necessário adicionar esta linha ao arquivo Gradle.

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

Ao fazer isso, você pode acessar seu recurso com:

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

Tenho procurado por isso e não consegui encontrar uma resposta, então decidi ajudar outras pessoas aqui.

Raphael Ayres
fonte
1

Na verdade, isso é o que funcionou para mim com os testes de instrumentação (executando o Android Studio versão 3.5.3 , Android Gradle Plugin versão 3.5.3 , Gradle versão 6.0.1 ):

  1. Coloque seus arquivos na src/androidTest/assetspasta
  2. Em seu arquivo de teste:

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

Michele
fonte