로컬 단위 테스트 빌드

로컬 테스트는 Android 기기나 에뮬레이터가 아닌 자체 워크스테이션에서 직접 실행됩니다. 따라서 Android 기기가 아닌 로컬 JVM (자바 가상 머신)을 사용하여 테스트를 실행합니다. 로컬 테스트를 사용하면 앱 로직을 더 빠르게 평가할 수 있습니다. 그러나 Android 프레임워크와 상호작용할 수 없으면 실행 가능한 테스트 유형에 제한이 생깁니다.

단위 테스트는 코드의 작은 섹션인 테스트 중인 단위의 동작을 확인합니다. 코드를 실행하고 결과를 확인하여 이 작업을 수행합니다.

단위 테스트는 일반적으로 간단하지만 테스트 중인 단위가 테스트 가능성을 염두에 두고 설계되지 않은 경우 설정이 문제가 될 수 있습니다.

  • 확인하려는 코드는 테스트에서 액세스할 수 있어야 합니다. 예를 들어 비공개 메서드는 직접 테스트할 수 없습니다. 대신 공개 API를 사용하여 클래스를 테스트합니다.
  • 격리로 단위 테스트를 실행하려면 테스트 중인 단위의 종속 항목을 가짜 또는 기타 테스트 더블과 같이 개발자가 제어하는 구성요소로 대체해야 합니다. 코드가 Android 프레임워크에 종속된 경우 특히 문제가 됩니다.

Android의 일반적인 단위 테스트 전략을 알아보려면 테스트할 항목을 참고하세요.

로컬 테스트 위치

기본적으로 로컬 단위 테스트의 소스 파일은 module-name/src/test/에 배치됩니다. 이 디렉터리는 Android 스튜디오를 사용하여 새 프로젝트를 만들 때 이미 존재합니다.

테스트 종속 항목 추가

또한 JUnit 테스트 프레임워크에서 제공하는 표준 API를 사용하도록 프로젝트의 테스트 종속 항목을 구성해야 합니다.

이렇게 하려면 앱 모듈의 build.gradle 파일을 열고 다음 라이브러리를 종속 항목으로 지정합니다. testImplementation 함수를 사용하여 이 함수가 애플리케이션이 아닌 로컬 테스트 소스 세트에 적용됨을 나타냅니다.

dependencies {
  // Required -- JUnit 4 framework
  testImplementation "junit:junit:$jUnitVersion"
  // Optional -- Robolectric environment
  testImplementation "androidx.test:core:$androidXTestVersion"
  // Optional -- Mockito framework
  testImplementation "org.mockito:mockito-core:$mockitoVersion"
  // Optional -- mockito-kotlin
  testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion"
  // Optional -- Mockk framework
  testImplementation "io.mockk:mockk:$mockkVersion"
}

로컬 단위 테스트 클래스 만들기

로컬 단위 테스트 클래스를 JUnit 4 테스트 클래스로 작성합니다.

이렇게 하려면 일반적으로 module-name/src/test/에 하나 이상의 테스트 메서드가 포함된 클래스를 만듭니다. 테스트 메서드는 @Test 주석으로 시작하며 테스트하려는 구성요소의 단일 측면을 실행하고 확인하기 위한 코드를 포함합니다.

다음 예는 로컬 단위 테스트 클래스를 구현하는 방법을 보여줍니다. 테스트 메서드 emailValidator_correctEmailSimple_returnsTrue()는 앱 내의 메서드인 isValidEmail()의 확인을 시도합니다. isValidEmail()도 true를 반환하면 테스트 함수는 true를 반환합니다.

Kotlin


import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test

class EmailValidatorTest {
  @Test fun emailValidator_CorrectEmailSimple_ReturnsTrue() {
    assertTrue(EmailValidator.isValidEmail("name@email.com"))
  }

}

Java


import org.junit.Test;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

class EmailValidatorTest {
  @Test
  public void emailValidator_CorrectEmailSimple_ReturnsTrue() {
    assertTrue(EmailValidator.isValidEmail("name@email.com"));
  }
}

앱의 구성요소가 예상 결과를 반환하는지 여부를 평가하는 읽기 쉬운 테스트를 만들어야 합니다. junit.Assert, Hamcrest 또는 Truth와 같은 어설션 라이브러리를 사용하는 것이 좋습니다. 위 스니펫은 junit.Assert를 사용하는 방법의 예입니다.

모의 가능한 Android 라이브러리

로컬 단위 테스트를 실행하면 Android Gradle 플러그인에 Android 프레임워크의 모든 API가 포함되어 있고 프로젝트에 사용된 버전에 맞게 수정된 라이브러리가 포함됩니다. 라이브러리는 이러한 API의 모든 공개 메서드와 클래스를 보유하지만 메서드 내부의 코드는 삭제되었습니다. 메서드 중 하나라도 액세스되면 테스트에서 예외가 발생합니다.

따라서 Context와 같은 Android 프레임워크의 클래스를 참조할 때 로컬 테스트를 빌드할 수 있습니다. 더 중요한 점은 Android 클래스에서 모의 처리 프레임워크를 사용할 수 있다는 것입니다.

Android 종속 항목 모의 처리

일반적인 문제는 클래스가 문자열 리소스를 사용 중인지 확인하는 것입니다. Context 클래스의 getString() 메서드를 호출하여 문자열 리소스를 가져올 수 있습니다. 그러나 로컬 테스트는 Context 또는 Android 프레임워크에 속한 메서드를 사용할 수 없습니다. 이상적으로는 getString() 호출을 클래스에서 제거하지만 이것이 항상 실용적이지는 않습니다. 해결 방법은 getString() 메서드가 호출될 때 항상 같은 값을 반환하는 Context의 모의 또는 스텁을 만드는 것입니다.

Mockable Android 라이브러리와 Mockito 또는 MockK와 같은 모의 프레임워크를 사용하여 단위 테스트에서 Android 클래스의 모의 동작을 프로그래밍할 수 있습니다.

Mockito를 사용하여 로컬 단위 테스트에 모의 객체를 추가하려면 다음 프로그래밍 모델을 따르세요.

  1. 테스트 환경 설정에 설명된 대로 Mockito 라이브러리 종속 항목을 build.gradle 파일에 포함합니다.
  2. 단위 테스트 클래스 정의의 시작 부분에 @RunWith(MockitoJUnitRunner.class) 주석을 추가합니다. 이 주석은 프레임워크 사용이 올바른지 확인하고 모의 객체의 초기화를 간소화하도록 Mockito 테스트 실행기에 알립니다.
  3. Android 종속 항목의 모의 객체를 만들려면 필드 선언 앞에 @Mock 주석을 추가합니다.
  4. 종속 항목의 동작을 스터브하기 위해 when()thenReturn() 메서드를 사용하여 조건 및 조건 충족 시 반환 값을 지정할 수 있습니다.

다음 예는 Mockito-Kotlin으로 만든 Kotlin에서 모의 Context 객체를 사용하는 단위 테스트를 만드는 방법을 보여줍니다.

import android.content.Context
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.junit.MockitoJUnitRunner
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock

private const val FAKE_STRING = "HELLO WORLD"

@RunWith(MockitoJUnitRunner::class)
class MockedContextTest {

  @Mock
  private lateinit var mockContext: Context

  @Test
  fun readStringFromContext_LocalizedString() {
    // Given a mocked Context injected into the object under test...
    val mockContext = mock<Context> {
        on { getString(R.string.name_label) } doReturn FAKE_STRING
    }

    val myObjectUnderTest = ClassUnderTest(mockContext)

    // ...when the string is returned from the object under test...
    val result: String = myObjectUnderTest.getName()

    // ...then the result should be the expected one.
    assertEquals(result, FAKE_STRING)
  }
}

Mockito 프레임워크 사용에 관한 자세한 내용은 Mockito API 참조샘플 코드SharedPreferencesHelperTest 클래스를 참고하세요. Android 테스트 Codelab도 사용해 보세요.

오류: "메서드의 ... 모의 개체가 생성되지 않았습니다."

Error: "Method ... not mocked 메시지로 Mockable Android 라이브러리의 메서드에 액세스하려고 하면 Mockable Android 라이브러리에서 예외가 발생합니다.

발생한 예외가 테스트에 문제가 되는 경우 반환 유형에 따라 메서드가 대신 null이나 0을 반환하도록 동작을 변경할 수 있습니다. 이렇게 하려면 Groovy에서 프로젝트 최상위 build.gradle 파일에 다음 구성을 추가합니다.

android {
  ...
  testOptions {
    unitTests.returnDefaultValues = true
  }