Android Studio 단위 테스트 : 데이터 (입력) 파일 읽기


96

단위 테스트에서 경로를 하드 코딩하지 않고 내 (데스크톱) 파일 시스템의 json 파일에서 데이터를 어떻게 읽을 수 있습니까?

정적 문자열을 만드는 대신 파일에서 테스트 입력 (내 구문 분석 방법에 대한)을 읽고 싶습니다.

파일은 내 단위 테스트 코드와 같은 위치에 있지만 필요한 경우 프로젝트의 다른 위치에 배치 할 수도 있습니다. Android Studio를 사용하고 있습니다.


3
IOUtils.toString (this.getClass (). getResourceAsStream ( "test_documents.json"), "UTF-8") 거의 모든 조합을 시도했지만 항상 null을 반환합니다. 아마도 파일이 항아리에 포함되지 않기 때문일 것입니다.
— Frank

Android 에뮬레이터 / 기기와 관련된 단위 테스트에 대해 이야기하고 있습니까?
— AndroidEx


@Frank는 어디에 배치 test_documents.json합니까? 자산 디렉토리?
— akhy

예, 에뮬레이터 / 장치를 포함하지 않는 새로운 단위 테스트 지원에 대해 이야기하고 있습니다. 라이브 APK와 함께 패키징되기 때문에 자산 디렉토리에 배치하지 않았습니다. 테스트 (java) 파일과 같은 폴더에 저장했습니다.
— Frank

답변:


149

android-gradle-plugin버전 에 따라 :

1. 버전 1.5 이상 :

json 파일을 넣고 다음 src/test/resources/test.json과 같이 참조하십시오.

classLoader.getResource("test.json"). 

gradle 수정이 필요하지 않습니다.

2. 1.5 미만 버전 : (또는 위의 솔루션이 작동하지 않는 경우)

  1. Android Gradle 플러그인 버전 1.1 이상을 사용하고 있는지 확인하세요 . 링크를 따라 Android Studio를 올바르게 설정하십시오.

  2. test디렉터리를 만듭니다 . 단위 테스트 클래스를 java디렉터리에 넣고 리소스 파일을 res디렉터리에 넣습니다 . Android Studio는 다음과 같이 표시해야합니다.

    여기에 이미지 설명 입력

  3. gradle리소스를 클래스 디렉토리에 복사하여 다음에 대해 볼 수 있도록 작업을 만듭니다 classloader.

    android{
       ...
    }
    
    task copyResDirectoryToClasses(type: Copy){
        from "${projectDir}/src/test/res"
        into "${buildDir}/intermediates/classes/test/debug/res"
    }
    
    assembleDebug.dependsOn(copyResDirectoryToClasses)
  4. 이제이 메서드를 사용 File하여 파일 리소스에 대한 참조 를 가져올 수 있습니다.

    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. 전체 클래스 또는 특정 테스트 방법에서 Ctrl+ Shift+로 단위 테스트를 실행 F10합니다.

1
대박! 악기 테스트가없는 편집은 매력처럼 작동합니다. 감사합니다!
— Frank

4
좋은 해결책이지만 항상 작동하지는 않습니다. 정리 작업을 실행 한 다음 testDebug를 실행하면 실패합니다. 기본적으로 개발자는 testDebug 전에 assembleDebug 작업을 실행해야 함을 알아야합니다. 이것을 개선하기위한 제안이 있습니까?
— joaoprudencio 2015

18
Android 플러그인 1.5.0이 포함 된 AndroidStudio 1.5를 사용하여 여기에 json 파일을 배치 src/test/resources/test.json하고 classLoader.getResource("test.json"). gradle 수정이 필요하지 않습니다. 내부의 중첩 폴더 resources도 작동합니다.
— Sergii Pechenizkyi

6
불완전한 답변입니다. 무엇입니까 classLoader? 이 코드 줄을 어디에 배치할까요? 반환 결과로 무엇을 할 수 있습니까?. 더 완전한 코드를 제공하십시오. -1
— voghDev

3
./src/test/resources/file.txtKotlin에서 읽기 :TestClassName::class.java.getResource("/file.txt")!!.readText()
— Erik

76

로컬 단위 테스트 (대 계측 테스트)의 경우 파일을 아래에 놓고 src/test/resourcesclassLoader를 사용하여 읽을 수 있습니다. 예를 들어 다음 코드 myFile.txt는 리소스 디렉터리에서 파일을 엽니 다 .

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

그것은 함께 일했습니다

  • 안드로이드 스튜디오 1.5.1
  • gradle 플러그인 1.3.1

이 날 여기 내 질문을 참조하십시오 작동하지 않습니다 stackoverflow.com/questions/36295824/...
— 타일러 파프

5
이것은 "src / test / res"에서 "src / test / resources"로 변경했을 때 저에게 효과적이었습니다. Android Studio 2.0 RC 3 사용, gradle : 2.0.0-rc3
— Alex Bravo

예상대로 작동했습니다. 그러나 파일이 "src / test / resources /"예 : "rules.xml"에서 사용 가능하지 않은 경우에도 테스트는 통과되지만이 경우 InputStream 결과는 null입니다.
— anand krish 2010 년

4
kotlin :val myFile = ClassLoader.getSystemResource("myFile.txt").readText()
— jj.

매력처럼 일했다!
— Amit Bhandari 2019

15

제 경우 해결책은 gradle 파일에 추가하는 것이 었습니다.

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

AS 2.3.1에 의해 모든 것이 발견 된 후

javaClass.classLoader.getResourceAsStream("countries.txt")

1
나는 매우 비슷한 일을했다 (Kotlin) : 1. 폴더와 파일을 다음 위치에 만듭니다. root/app/src/test/resources/test.json 2. 다음과 같은 데이터를 읽습니다.val jsonFile = ClassLoader.getSystemResource("test.json").readText()
— jj.

8

Android Studio의 테스트 리소스에 많은 문제가 있었기 때문에 명확성을 위해 몇 가지 테스트를 설정했습니다. 내 mobile(Android Application) 프로젝트에서 다음 파일을 추가했습니다.

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

테스트 클래스 (모든 테스트 통과) :

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

동일한 루트 프로젝트에 .NET 이라는 Java (Android 아님) 프로젝트 가 data있습니다. 데이터 프로젝트에 동일한 파일을 추가하는 경우 :

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

그런 다음 위의 모든 테스트는 Android Studio에서 실행하면 실패하지만 명령 줄에서 ./gradlew data:test. 그것을 우회하기 위해 나는이 해킹을 사용합니다 (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"))
}

용법: resource('/test.txt')

Android 스튜디오 2.3, Gradle 3.3


훌륭한 답변 (45 분 검색 후 😌). 여러 문제의 핵심을 파악하고 테스트 자체를 사용하여 결과를 쉽게 복제 할 수 있습니다. Fwiw, AS 2.3.1, Gradle 2.3.1에서는 getClassLoader()버전이 예상대로 작동합니다. 즉, Android Studio와 macOS 컴퓨터의 명령 줄 및 Linux CI 서버 (CircleCI)에서 실행되는 파일을 찾습니다. 그래서 나는 그것과 함께 가고 Gradle 3.3이 나중에 그것을 깨뜨리지 않기를 바라고있다 ...
— mm2001

좋은! 여기에 동일한 리소스로드 문제가 있습니다. AS 2.3.2, Gradle 3.3. 테스트 build/resources/test는 대화 형 클래스 경로에 포함되지 않기 때문에 명령 줄에서 작동하지만 AS를 통해서는 작동 하지 않습니다.
— Mark McKenna

6

실행-> 구성 편집-> JUnit으로 이동 한 다음 단위 테스트에 대한 실행 구성을 선택하면 '작업 디렉터리'설정이 있습니다. json 파일이있는 곳을 가리켜 야합니다. 이로 인해 다른 테스트가 중단 될 수 있습니다.


this.getClass (). getResourceAsStream (test.json)을 사용하는 것보다? 프로젝트의 루트에 파일을 추가했지만 여전히 파일을 찾지 못했습니다.
— Frank

new File()또는 이와 유사한 방법을 사용하여 파일을로드하는 데 사용할 수 있지만 위에서 설명한 클래스 경로로드 방법에서는 직접 작동하지 않습니다. 또한 각각의 새로운 실행 구성은 작업 디렉토리를 설정해야하고 기본적으로 AS 및 Gradle 명령 줄은 서로 다른 작업 디렉토리를 사용하기를 원하기 때문에 약간 까다 롭습니다. 이러한 고통
— Mark McKenna

5

여기에 내 결과를 추가해야하지만. 이것이 조금 오래되었다는 것을 알고 있지만 src / test / resources 디렉토리가 없지만 전체 프로젝트에 대해 하나의 리소스 디렉토리 만있는 Gradle의 최신 버전의 경우이 줄을 Gradle 파일에 추가해야합니다.

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

이렇게하면 다음을 통해 리소스에 액세스 할 수 있습니다.

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

나는 이것을 찾고 있었지만 답을 찾을 수 없어서 다른 사람들을 돕기로 결정했습니다.


1

실제로 이것은 Instrumentation Tests (Android Studio 버전 3.5.3 , Android Gradle Plugin 버전 3.5.3 , Gradle 버전 6.0.1 실행 ) 에서 저에게 효과적이었습니다 .

  1. src/androidTest/assets폴더에 파일 넣기
  2. 테스트 파일에서 :

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.