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.


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.

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

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

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


Ó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.


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.


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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.