단말기를 연결하거나 에뮬레이터를 실행해야 수행 가능한 Instrumentation Test와 달리, 유닛 테스트는 자체적으로 테스트를 수행할 수 있어 매우 편리합니다.

안드로이드 스튜디오에서도 유닛 테스트를 지원하게 되어 이전보다 더 편리하게 테스트를 작성할 수 있게 되었는데, 테스트 커버리지(Coverage)를 측정은 자체적으로 지원하지 않아 별도 설정이 필요합니다.

테스트 코드 작성

테스트 커버리지는 전체 테스트 가능한 코드 중 테스트 된 코드의 비중을 측정하는 작업이므로, 테스트 코드 없이는 수행되지 않습니다.

따라서, 테스트 코드를 작성하기 위해 먼저 다음과 같이 간단한 클래스를 작성합니다.

[Calculator.java]

public class Calculator {

    public static int sum(int a, int b) {
        return a + b;
    }

    public static int sub(int a, int b) {
        return a - b;
    }
}

다음, Calculator 클래스의 테스트 코드를 작성합니다. 유닛 테스트로 수행할 코드이므로 src/androidTest/java가 아닌 src/test/java 하위 폴더에 추가해야 하는 것에 유념하세요.

[CalculatorTest.java]

public class CalculatorTest {

    @Test
    public void testSum() {
        assertEquals(5, Calculator.sum(2, 3));
    }

}

빌드 스크립트 수정

유닛 테스트를 수행할 모듈의 빌드 스크립트(build.gradle)에 다음과 같이 테스트 커버리지를 측정하는 태스크를 추가합니다. 여기에서는 JaCoCo를 사용하여 커버리지를 측정합니다.

apply plugin: 'com.android.application'

android {
    ...
}

dependencies {
    ...
}

apply plugin: 'jacoco'

jacoco {
    reportsDir = file("${buildDir}/reports")
}

task coverageReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') {
    group = "Reporting"
    description = "Generate Jacoco coverage reports"

    def coverageSourceDirs = ['src/main/java']

    classDirectories = fileTree(
            dir: "${buildDir}/intermediates/classes/debug",
            excludes: ['**/R.class',
                       '**/R$*.class',
                       '**/BuildConfig.*',
                       '**/Manifest*.*',
                       'com/android/**/*.class']
    )

    sourceDirectories = files(coverageSourceDirs)
    executionData = files("${buildDir}/jacoco/testDebugUnitTest.exec")

    reports {
        xml.enabled = true
        html.enabled = true
    }
}

추가해 준 구문을 부분별로 조금 더 자세히 살펴봅시다.

JaCoCo 플러그인 설정

apply plugin: 'jacoco'

jacoco {
    reportsDir = file("${buildDir}/reports")
}

빌드 스크립트에서 JaCoCo를 사용할 수 있도록 하고, 측정 결과가 저장될 경로를 지정합니다.

커버리지 측정 태스크 정의

task coverageReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') {
    group = "Reporting"
    description = "Generate Jacoco coverage reports"

    def coverageSourceDirs = ['src/main/java']

    classDirectories = fileTree(
            dir: "${buildDir}/intermediates/classes/debug",
            excludes: ['**/R.class',
                       '**/R$*.class',
                       '**/BuildConfig.*',
                       '**/Manifest*.*',
                       'com/android/**/*.class']
    )

    sourceDirectories = files(coverageSourceDirs)
    executionData = files("${buildDir}/jacoco/testDebugUnitTest.exec")

    reports {
        xml.enabled = true
        html.enabled = true
    }
}
  • dependsOn: 테스트 수행 후 커버리지 측정이 진행될 수 있도록, 유닛 테스트를 수행하는 태스크 이름으로 지정합니다. 사용하는 안드로이드 그래들 빌드 플러그인 버전에 따라 다르게 지정해야 하며, 사용 중인 플러그인 버전은 루트 프로젝트의 build.gradle에서 확인할 수 있습니다. 버전별로 지정해야 하는 이름은 다음과 같습니다.
    • 1.2.3 이하: testDebug
    • 1.3.0 이상: testDebugUnitTest
  • coverageSourceDirs(sourceDirectories): 커버리지를 측정할 소스 디렉터리를 지정합니다.
  • classDirectories: 소스 디렉터리 내 클래스를 컴파일한 결과인 *.class 파일이 있는 디렉터리를 지정합니다. 커버리지 측정에서 제외해야 하는 클래스(R, 안드로이드 서포트 라이브러리 등)는 제외합니다.
  • executionData: 커버리지 측정 결과를 저장할 파일 이름을 지정합니다. 플러그인 버전에 따라 다르게 지정합니다.
    • 1.2.3 이하: testDebug.exec
    • 1.3.0 이상: testDebugUnitTest.exec
  • reports: 커버리지 결과 리포트 형식을 지정합니다.

커버리지 측정

./gradlew :app:coverageReport를 사용하여 커버리지를 측정합니다. (Windows일 경우 gradlew.bat :app:coverageReport)

측정 결과는 app/build/reports/coverageReport에 생성되며, html 폴더 내에서 다음과 같이 HTML 형태로 된 측정 결과를 확인할 수 있습니다.

본 포스트에서 사용한 예제 프로젝트의 전체 소스 코드는 아래에서 확인 가능합니다.

김태호 (Taeho Kim)

안드로이드와 오픈소스, 코틀린(Kotlin)에 관심이 많습니다. 현재 Google Developer Groups(GDG) Korea Android 운영자와 Google Developer Expert(GDE)로 활동하고 있습니다.

kunny Androidhuman


Published