자체 계측 테스트 예

계측 테스트가 시작되면 삽입된 계측 코드로 타겟 패키지가 다시 시작되어 실행이 시작됩니다. 한 가지 예외라면 여기서 타겟 패키지는 Android 애플리케이션 프레임워크 자체(예: android 패키지)가 될 수 없습니다. 그렇게 되면 계측 자체를 포함하여 시스템 기능을 지원하는 역할을 하는 Android 프레임워크가 다시 시작되어야 하는 역설적인 상황이 발생하기 때문입니다.

이는 실행을 위해 계측 테스트를 시스템 서버라고도 하는 Android 프레임워크에 직접 삽입할 수 없다는 의미입니다. Android 프레임워크를 테스트하기 위해 테스트 코드는 공개 API 노출 영역, 또는 플랫폼 소스 트리에서 사용할 수 있는 Android 인터페이스 정의 언어(AIDL)를 통해 노출된 것만 호출할 수 있습니다. 이 테스트 카테고리에서는 특정 패키지를 타겟팅하는 것이 중요한 것은 아닙니다. 따라서, 일반적으로 이러한 계측은 테스트 애플리케이션 패키지 자체의 AndroidManifest.xml 파일의 <manifest> 태그에 정의된 것처럼 계측 테스트 애플리케이션 패키지를 타겟팅하도록 선언됩니다.

요구사항에 따라 이 카테고리의 테스트 애플리케이션 패키지는 다음과 같습니다.

  • 테스트에 필요한 활동을 번들로 제공할 수 있습니다.
  • 사용자 ID를 시스템과 공유할 수 있습니다.
  • 플랫폼 키로 서명할 수 있습니다.
  • 공개 SDK가 아닌 프레임워크 소스에 대해 컴파일될 수 있습니다.

이 계측 테스트 카테고리는 경우에 따라 자체 계측이라고 합니다. 다음은 플랫폼 소스의 자체 계측 테스트 예입니다.

여기에서 다루는 예는 자체 테스트 애플리케이션 패키지에 설정된 타겟 패키지로 새로운 계측 테스트를 작성하는 것입니다. 이 가이드에서는 다음 테스트를 예로 사용합니다.

계속 진행하기 전에 먼저 코드를 탐색하여 대략적인 느낌을 파악하는 것이 좋습니다.

소스 위치 결정

일반적으로 개발팀에는 이미 코드를 체크인할 수 있는 위치 및 테스트를 추가할 수 있는 위치의 패턴이 마련되어 있습니다. 대부분의 팀에는 하나의 git 저장소가 있거나, git 저장소는 다른 팀과 공유하지만 구성요소 소스 코드를 포함하는 팀 전용 하위 디렉터리가 있습니다.

구성요소 소스의 루트 위치가 <component source root>이고 그 아래 대부분의 구성요소를 포함하는 srctests 폴더가 있으며 Android.mk(또는 세분된 추가 .mk 파일), 매니페스트 파일(AndroidManifest.xml) 및 테스트 구성 파일('AndroidTest.xml')이 있다고 가정합니다.

완전히 새로운 테스트를 추가하고 있으므로 구성요소 src 옆에 tests 디렉터리를 만들고 콘텐츠를 채워야 할 수 있습니다.

경우에 따라, 개별 apk에 다양한 테스트 모음을 패키징해야 하므로 팀에서 tests 아래 더 깊은 디렉터리 구조를 가질 수도 있습니다. 이 경우 tests 아래에 새 하위 디렉터리를 만들어야 합니다.

구조와 관계없이 tests 디렉터리나 새로 만든 하위 디렉터리는 결국 샘플 gerrit 변경의 instrumentation 디렉터리에 있는 것과 비슷한 파일로 채우게 됩니다. 각 파일의 세부정보는 이 문서의 뒷부분을 참고하세요.

매니페스트 파일

앱 프로젝트와 마찬가지로 각 계측 테스트 모듈에는 AndroidManifest.xml이라는 매니페스트 파일이 있어야 합니다. BUILD_PACKAGE 코어 makefile을 사용하여 이 파일을 자동으로 포함하려면 테스트 모듈의 Android.mk 파일 옆에 이 파일을 제공합니다.

AndroidManifest.xml 파일에 익숙하지 않다면 앱 매니페스트 개요를 참고하세요.

다음은 샘플 AndroidManifest.xml 파일입니다.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  android:sharedUserId="android.uid.system"
  package="android.test.example.helloworld" >

    <application>
       <uses-library android:name="android.test.runner"/>
    </application>

    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
                     android:targetPackage="android.test.example.helloworld"
                     android:label="Hello World Test"/>

</manifest>

매니페스트 파일의 일부 리마크는 다음과 같습니다.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="android.test.example.helloworld" >

package 속성은 애플리케이션 패키지 이름입니다. 이는 고유한 식별자로 Android 애플리케이션 프레임워크에서 애플리케이션(여기서는 테스트 애플리케이션)을 식별하는 데 사용합니다. 시스템의 각 사용자는 해당 패키지 이름을 가진 애플리케이션을 하나만 설치할 수 있습니다.

또한, 이 package 속성은 ComponentName#getPackageName()에서 반환하는 것과 동일하며 개발자가 adb shell을 통해 다양한 pm 하위 명령어와 상호작용하는 데 사용하는 것과 동일합니다.

패키지 이름은 일반적으로 Java 패키지 이름과 같은 형식이지만 실제로는 거의 관계가 없다는 점에 유의하세요. 즉, 애플리케이션(또는 테스트) 패키지에 포함되는 클래스는 어떤 패키지 이름이든 가질 수 있지만, 단순화하기 위해 애플리케이션 또는 테스트의 최상위 Java 패키지 이름을 애플리케이션 패키지 이름과 동일하게 할 수 있습니다.

android:sharedUserId="android.uid.system"

이는 설치 시 이 APK 파일에 핵심 플랫폼과 동일한 사용자 ID, 즉 런타임 ID를 부여해야 함을 선언합니다. 이는 핵심 플랫폼(위 섹션의 LOCAL_CERTIFICATE 참고)과 동일한 인증서로 서명된 apk에 종속적이지만 개념은 다양합니다.

  • 일부 권한 또는 API가 서명으로 보호되므로 동일한 서명 인증서가 필요함
  • 일부 권한 또는 API에 호출자의 system 사용자 ID가 필요하며, 호출자가 코어 플랫폼 자체가 아닌 별도의 패키지인 경우 system과 사용자 ID를 공유하기 위한 호출 패키지가 필요함
<uses-library android:name="android.test.runner" />

이는 관련 클래스가 별도의 프레임워크 JAR 라이브러리 파일에 패키징되므로 모든 계측 테스트에 필요합니다. 따라서, 애플리케이션 프레임워크에서 테스트 패키지를 호출할 때 추가 클래스 경로 항목이 필요합니다.

android:targetPackage="android.test.example.helloworld"

여기서 targetPackage가 이 파일의 manifest 태그에 선언된 package 속성과 동일하게 선언되었음을 알 수 있습니다. 테스트 기본에서 언급했듯이 이 계측 테스트 카테고리는 일반적으로 프레임워크 API를 테스트하기 위한 것이므로 프레임워크 자체 외에 타겟팅하는 특정 애플리케이션 패키지를 보유하는 것은 크게 의미가 없습니다.

간단한 구성 파일

새로운 각 테스트 모듈에는 모듈 메타데이터, 컴파일 시간 종속 항목 및 패키징 지침으로 빌드 시스템을 안내할 구성 파일이 있어야 합니다. 대부분은 Soong 기반의 Blueprint 파일 옵션으로 충분합니다. 자세한 내용은 간단한 테스트 구성을 참고하세요.

복잡한 구성 파일

더욱 복잡한 경우에는 Android 테스트 하네스, Trade Federation용 테스트 구성 파일도 작성해야 합니다.

테스트 구성에서는 특별한 기기 설정 옵션과 테스트 클래스 공급에 사용할 기본 인수를 지정할 수 있습니다. /platform_testing/tests/example/instrumentation/AndroidTest.xml에서 테스트 구성 예를 참고하세요.

편의를 위해 여기에 개요가 포함되어 있습니다.

<configuration description="Runs sample instrumentation test.">
  <target_preparer class="com.android.tradefed.targetprep.TestFilePushSetup"/>
  <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
    <option name="test-file-name" value="HelloWorldTests.apk"/>
  </target_preparer>
  <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"/>
  <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"/>
  <option name="test-suite-tag" value="apct"/>
  <option name="test-tag" value="SampleInstrumentationTest"/>

  <test class="com.android.tradefed.testtype.AndroidJUnitTest">
    <option name="package" value="android.test.example.helloworld"/>
    <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
  </test>
</configuration>

테스트 구성 파일의 일부 리마크는 다음과 같습니다.

<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
  <option name="test-file-name" value="HelloWorldTests.apk"/>
</target_preparer>

이 코드는 지정된 target_preparer를 사용하여 대상 기기에 HelloWorldTests.apk를 설치하도록 Trade Federation에 지시합니다. Trade Federation에는 개발자가 사용할 수 있는 타겟 준비자가 많으므로 테스트를 실행하기 전에 기기가 제대로 설정되어 있는지 확인하는 데 사용할 수 있습니다.

<test class="com.android.tradefed.testtype.AndroidJUnitTest">
  <option name="package" value="android.test.example.helloworld"/>
  <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
</test>

이는 테스트를 실행하는 데 사용할 Trade Federation 테스트 클래스를 지정하고, 실행할 기기의 패키지와 테스트 실행자 프레임워크(이 경우 JUnit)를 전달합니다.

자세한 내용은 테스트 모듈 구성을 참고하세요.

JUnit4 기능

android-support-test 라이브러리를 테스트 실행자로 사용하면 새 JUnit4 형식의 테스트 클래스를 채택할 수 있고 샘플 gerrit 변경에는 기능의 일부 기본적인 사용이 포함됩니다. /platform_testing/tests/example/instrumentation/src/android/test/example/helloworld/HelloWorldTest.java에서 예시를 참고하세요.

테스트 패턴은 일반적으로 구성요소팀에 따라 다르지만, 일반적으로 유용한 사용 패턴이 있습니다.

@RunWith(JUnit4.class)
public class HelloWorldTest {

JUnit4의 주요 차이점은 테스트를 더 이상 공통 기본 테스트 클래스에서 상속하지 않아도 된다는 점입니다. 대신, 일반 자바 클래스로 테스트를 작성하고 주석을 사용하여 특정 테스트 설정 및 제약 조건을 표시합니다. 이 예에서는 이 클래스를 JUnit4 테스트로 실행하도록 합니다.

    @BeforeClass
    public static void beforeClass() {
    ...
    @AfterClass
    public static void afterClass() {
    ...
    @Before
    public void before() {
    ...
    @After
    public void after() {
    ...
    @Test
    @SmallTest
    public void testHelloWorld() {
    ...

@Before@After 주석은 JUnit4가 메서드에서 사전 테스트 설정을 실행하고 테스트 후 해제하는 데 사용됩니다. 마찬가지로, @BeforeClass@AfterClass 주석은 JUnit4가 테스트 클래스에서 모든 테스트를 실행하기 전에 설정을 진행하고 나중에 해제하는 데 사용됩니다. 클래스 범위 설정 및 해제 메서드는 정적 메서드이어야 합니다. 테스트 메서드의 경우 이전 버전의 JUnit과 달리 메서드 이름을 test로 시작할 필요가 없으며 대신 각각 @Test 주석을 달아야 합니다. 평상시처럼 테스트 메서드는 공개 상태여야 하며, 반환 값을 선언하지 않고, 매개변수를 사용하지 않습니다. 또한, 예외가 발생할 수 있습니다.

클래스 액세스 계측

Hello World 기본 예에서는 다루지 않지만, Android 테스트에서 Instrumentation 인스턴스에 대한 액세스가 필요한 것이 일반적입니다. 이 인터페이스는 애플리케이션 컨텍스트, 테스트 API 관련 활동 수명 주기 등에 대한 액세스를 제공하는 핵심 API 인터페이스입니다.

JUnit4 테스트에는 더 이상 공통 기본 클래스가 필요하지 않으므로 대신 InstrumentationTestCase#getInstrumentation()을 통해 Instrumentation 인스턴스를 가져오지 않아도 됩니다. 대신, 새로운 테스트 실행자는 계측 프레임워크에서 생성한 컨텍스트 및 환경 설정이 저장된 InstrumentationRegistry를 통해 인스턴스를 관리합니다.

Instrumentation 클래스의 인스턴스에 액세스하려면 InstrumentationRegistry 클래스의 정적 메서드 getInstrumentation()을 호출하기만 하면 됩니다.

Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation()

로컬에서 빌드 및 테스트

가장 일반적인 사용 사례에는 Atest를 사용하세요.

보다 심도 깊은 맞춤설정이 필요한 복잡한 사례인 경우 계측 안내를 따르세요.