테스트 매핑

테스트 매핑을 간단하게 소개하고 Android 오픈소스 프로젝트 (AOSP)에서 테스트를 구성하는 방법을 설명합니다.

테스트 매핑 정보

테스트 매핑은 Gerrit 기반 접근 방식으로, 개발자는 Android 소스 트리에서 사전 제출 및 사후 제출 테스트 규칙을 직접 만들고 테스트할 브랜치와 기기의 결정을 테스트 인프라에 맡길 수 있습니다. 테스트 매핑의 정의는 모든 소스 디렉터리에 배치할 수 있는 TEST_MAPPING이라는 이름의 JSON 파일입니다.

AtestTEST_MAPPING 파일을 사용하여 관련 디렉터리에서 사전 제출 테스트를 실행할 수 있습니다. 테스트 매핑을 사용하면 Android 소스 트리 내에서 최소한의 변경으로 사전 제출 검사에 동일한 테스트 세트를 추가할 수 있습니다.

다음 예를 참고하세요.

테스트 매핑은 Trade Federation (TF) 테스트 하네스를 사용하여 테스트를 실행하고 결과를 보고합니다.

테스트 그룹 정의

테스트 매핑은 테스트 그룹 을 통해 테스트를 그룹화합니다. 테스트 그룹의 이름은 임의의 문자열일 수 있습니다. 예를 들어 presubmit 은 변경사항을 확인할 때 실행할 테스트 그룹의 이름일 수 있습니다. 그리고 postsubmit 은 변경사항을 병합한 후 빌드를 확인하는 데 사용되는 테스트일 수 있습니다.

빌드 스크립트 규칙 패키징

Trade Federation 테스트 하네스에서 특정 빌드에 대해 테스트 매핑의 테스트 모듈을 실행하려면 다음 2개의 모음 중 하나에 대해 Soong에 `test_suites`를 설정하고 Make에 `LOCAL_COMPATIBILITY_SUITE`를 설정해야합니다.test_suitesLOCAL_COMPATIBILITY_SUITE

  • general-tests 는 기기별 기능에 종속되지 않는 테스트 (예: 대부분의 기기에 없는 공급업체별 하드웨어)에 사용됩니다. 대부분의 테스트는 하나의 ABI나 비트율 또는 HWASan과 같은 하드웨어 기능 (ABI마다 별도의 test_suites 타겟이 있음)과 관련된 경우 및 기기에서 실행해야 하는 경우에도 general-tests 모음에 있어야 합니다.
  • device-tests는 기기별 기능에 종속되는 테스트에 사용됩니다. 일반적으로 이러한 테스트는 vendor/ 아래에 있습니다. 기기별하나의 기기에 고유한 기능만 의미하므로 ABI별이더라도 일반적으로 general-tests로 표시해야 하는 GTest 테스트뿐만 아니라 JUnit 테스트에도 적용됩니다.

예:

Android.bp: test_suites: ["general-tests"],
Android.mk: LOCAL_COMPATIBILITY_SUITE := general-tests

테스트 모음에서 실행되도록 테스트 구성

테스트 모음 내에서 테스트가 실행되려면 테스트는 다음을 충족해야 합니다.

  • 빌드 제공업체가 없어야 합니다.
  • 작업이 완료된 후에는 정리해야 합니다(예: 테스트 중에 생성된 임시 파일 삭제).
  • 시스템 설정을 기본값 또는 원래 값으로 변경해야 합니다.
  • 기기가 특정 상태에 있는 것으로 가정해서는 안 됩니다(예: 루트 준비). 대부분의 테스트는 실행하는 데 루트 권한이 필요하지 않습니다. 테스트에 루트가 있어야 하는 경우 RootTargetPreparer를 사용하여 AndroidTest.xml에 지정해야 합니다. 다음 예와 같습니다.

    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
    

테스트 매핑 파일 만들기

테스트 범위가 필요한 디렉터리의 경우 예와 같이 TEST_MAPPING JSON 파일 을 추가합니다. 이러한 규칙은 해당 디렉터리 또는 하위 디렉터리에서 파일이 터치될 때 사전 제출 검사에서 테스트가 실행되도록 합니다.

다음은 샘플 TEST_MAPPING 파일(JSON 형식이지만 주석이 지원됨)입니다.

{
  "presubmit": [
    // JUnit test with options and file patterns.
    {
      "name": "CtsWindowManagerDeviceTestCases",
      "options": [
        {
          "include-annotation": "android.platform.test.annotations.RequiresDevice"
        }
      ],
      "file_patterns": ["(/|^)Window[^/]*\\.java", "(/|^)Activity[^/]*\\.java"]
    },
    // Device-side GTest with options.
    {
      "name" : "hello_world_test",
      "options": [
        {
          "native-test-flag": "\"servicename1 servicename2\""
        },
        {
          "native-test-timeout": "6000"
        }
      ]
    }
    // Host-side GTest.
    {
      "name" : "net_test_avrcp",
      "host" : true
    }
  ],
  "postsubmit": [
    {
      "name": "CtsDeqpTestCases",
      "options": [
        {
          // Use regex in include-filter which is supported in AndroidJUnitTest
          "include-filter": "dEQP-EGL.functional.color_clears.*"
        }
      ]
    }
  ],
  "imports": [
    {
      "path": "frameworks/base/services/core/java/com/android/server/am"
    }
  ]
}

속성 설정

에서 presubmitpostsubmit은 각 테스트 그룹의 이름입니다. 테스트 그룹에 관한 자세한 내용은 테스트 그룹 정의 를 참고하세요.

테스트 모듈의 이름 또는 Trade Federation 통합 테스트 이름 (테스트 XML 파일 리소스 경로, 예: uiautomator/uiautomator-demo) 은 name 속성의 값으로 설정할 수 있습니다. name 필드는 클래스 name 또는 테스트 메서드 name을 사용할 수 없습니다. 실행할 테스트의 범위를 좁히려면 include-filter와 같은 옵션을 사용하세요. include-filter 샘플 사용을 참고하세요.

host 설정은 테스트가 기기 없이 호스트에서 실행되는 테스트인지를 나타냅니다. 기본값은 false이며 테스트를 실행하려면 기기가 필요합니다. 지원되는 테스트 유형은 HostGTest GTest 바이너리의 경우 이고, JUnit 테스트의 경우 HostTest입니다.

file_patterns 속성을 사용하면 TEST_MAPPING 파일이 포함된 디렉터리를 기준으로 소스 코드 파일의 상대 경로와 일치하는 정규 표현식 문자열 목록을 설정할 수 있습니다. 이 에서 테스트 CtsWindowManagerDeviceTestCasesTEST_MAPPING 파일 또는 하위 디렉터리와 동일한 디렉터리에 있는 Window 또는 Activity로 시작하는 자바 파일이 변경될 때만 사전 제출로 실행됩니다. 역슬래시 (\)는 JSON 파일에 있으므로 이스케이프 처리되어야 합니다.

TEST_MAPPING 파일 가져오기

imports 속성을 사용하면 콘텐츠를 복사하지 않고 다른 TEST_MAPPING 파일에 테스트를 포함할 수 있습니다. 가져온 경로의 상위 디렉터리에 있는 TEST_MAPPING 파일도 포함됩니다. TEST_MAPPING 은 중첩 가져오기를 허용합니다. 즉, 가져온 파일 자체에서 다른 TEST_MAPPING 파일을 가져올 수 있으며 테스트 매핑은 포함된 테스트를 병합할 수 있습니다.

TEST_MAPPING은 루트 수준 가져오기와 그룹 수준 가져오기를 모두 지원합니다.

  • 루트 수준 가져오기: TEST_MAPPING 파일의 최상위 수준에서 지정됩니다 (테스트 그룹 외부). 루트 수준 가져오기는 가져오는 경로에 작성된 것처럼 전체 타겟 TEST_MAPPING 파일 (및 상위 디렉터리)을 가져옵니다. 가져온 파일의 모든 테스트 그룹 정의 (예: presubmit, postsubmit)는 가져오는 파일의 해당 테스트 그룹으로 병합됩니다.
  • 그룹 수준 가져오기: 특정 테스트 그룹(예: presubmit 또는 postsubmit) 내에서 직접 지정됩니다. 그룹 수준 가져오기는 해당 테스트 그룹으로 엄격하게 범위가 지정됩니다. 즉, 타겟 TEST_MAPPING 파일 내의 특정 그룹 아래에 정의된 테스트만 가져옵니다. 타겟 파일의 다른 모든 테스트 그룹은 무시됩니다.

그룹 수준 가져오기는 테스트 실행을 세밀하게 제어합니다. 예를 들어 가져온 디렉터리에서 대규모 사후 제출 테스트를 가져오지 않고 사전 제출을 위한 테스트만 가져올 수 있습니다.

루트 수준 가져오기의 예:

{
  "imports": [
    {
      "path": "frameworks/base/services/core"
    }
  ],
  "presubmit": [
    {
      "name": "MyTestModule"
    }
  ]
}

그룹 수준 가져오기의 예:

{
  "presubmit": [
    {
      "name": "MyTestModule"
    },
    {
      "imports": [
        {
          "path": "frameworks/base/services/core"
        }
      ]
    }
  ],
  "postsubmit": [
    {
      "imports": [
        {
          "path": "frameworks/base/services/accessibility"
        }
      ]
    }
  ]
}

options 속성에는 추가 Tradefed 명령줄 옵션이 있습니다.

테스트에 사용할 수 있는 옵션의 전체 목록을 보려면 다음을 실행합니다.

tradefed.sh run commandAndExit [test_module] --help

옵션의 작동 방식에 관한 자세한 내용은 Tradefed의 옵션 처리 를 참고하세요.

TEST_MAPPING 유효성 검사

TEST_MAPPING 파일을 수정하는 변경사항을 제출할 때 사전 제출 검사가 실행되어 정확성을 보장합니다.

  • 파일 패턴 유효성 검사: file_patterns의 모든 정규 표현식이 저장소의 하나 이상의 파일과 일치하는지 확인합니다. 파일과 일치하지 않는 오래된 패턴으로 인해 검사가 실패합니다.
  • 빌드 시간 유효성 검사: 빌드가 수집하는 빌드 시간 유효성 검사 경고를 기본 브랜치의 사전 제출에서 차단 오류로 승격합니다. 일반적인 경고는 다음과 같습니다.
    • 존재하지 않는 모듈: 이름에 오타가 있는 경우와 같이 코드베이스에 없는 테스트 모듈 이름을 참조합니다.
    • 잘못된 가져오기: imports에 존재하지 않거나 TEST_MAPPING 파일이 포함되지 않은 참조 경로입니다.
    • 스키마 문제: JSON 구성에서 지원되지 않는 키 또는 잘못된 구조를 사용합니다.

Atest로 테스트 실행

사전 제출 테스트 규칙을 로컬에서 실행하려면 다음 단계를 따르세요.

  1. TEST_MAPPING 파일이 포함된 디렉터리로 이동합니다.
  2. 다음 명령어를 실행합니다.

    atest
    

현재 디렉터리와 상위 디렉터리의 TEST_MAPPING 파일에 구성된 모든 사전 제출 테스트가 실행됩니다. Atest는 사전 제출에 관한 두 개의 테스트 (A 및 B)를 찾아 실행합니다.

현재 작업 디렉터리 (CWD) 및 상위 디렉터리의 TEST_MAPPING 파일에서 사전 제출 테스트를 실행하는 가장 간단한 방법입니다. Atest는 CWD 및 모든 상위 디렉터리에서 TEST_MAPPING 파일을 찾아 사용합니다.

소스 코드 구성

이 예에서는 소스 트리 전체에 TEST_MAPPING 파일을 구성하는 방법을 보여줍니다.

src
├── project_1
│   └── TEST_MAPPING
├── project_2
│   └── TEST_MAPPING
└── TEST_MAPPING

src/TEST_MAPPING의 콘텐츠:

{
  "presubmit": [
    {
      "name": "A"
    }
  ]
}

src/project_1/TEST_MAPPING의 콘텐츠

{
  "presubmit": [
    {
      "name": "B"
    }
  ],
  "postsubmit": [
    {
      "name": "C"
    }
  ],
  "other_group": [
    {
      "name": "X"
    }
  ]}

src/project_2/TEST_MAPPING의 콘텐츠

{
  "presubmit": [
    {
      "name": "D"
    }
  ],
  "import": [
    {
      "path": "src/project_1"
    }
  ]}

타겟 디렉터리 지정

타겟 디렉터리를 지정하여 디렉터리의 TEST_MAPPING 파일에서 테스트를 실행할 수 있습니다. 다음 명령어는 두 개의 테스트 (A, B)를 실행합니다.

atest --test-mapping src/project_1

사후 제출 테스트 규칙 실행

또한 이 명령어를 사용하여 src_path (기본값은 CWD)와 상위 디렉터리의 TEST_MAPPING에 정의된 사후 제출 테스트 규칙을 실행할 수 있습니다.

atest [--test-mapping] [src_path]:postsubmit

기기가 필요 없는 테스트만 실행

Atest에 --host 옵션을 사용하면 기기는 필요 없이 호스트에 대해 구성된 테스트만 실행할 수 있습니다. 이 옵션이 없으면 Atest는 기기가 필요한 테스트와 호스트에서 실행되어 기기가 필요 없는 테스트를 모두 실행합니다. 테스트는 두 개의 개별 모음에서 실행됩니다.

atest [--test-mapping] --host

테스트 그룹 식별

Atest 명령어에서 테스트 그룹을 지정할 수 있습니다. 다음 명령어는 src/project_1 디렉터리의 파일과 관련된 모든 postsubmit 테스트를 실행합니다. 해당 파일에는 하나의 테스트 (C)만 포함되어 있습니다.

또는 :all을 사용하여 그룹과 관계없이 모든 테스트를 실행할 수 있습니다. 다음 명령어는 A, B, C, X 등 4개의 테스트를 실행합니다.

atest --test-mapping src/project_1:all

하위 디렉터리 포함

기본적으로 TEST_MAPPING에서 Atest로 테스트를 실행하면 CWD (또는 지정된 디렉터리) 및 상위 디렉터리에 있는 TEST_MAPPING에 구성된 사전 제출 테스트만 실행됩니다. 하위 디렉터리의 모든 TEST_MAPPING 파일에서 테스트를 실행하려면 --include-subdir 옵션을 사용하여 강제로 Atest가 이러한 테스트도 포함하도록 합니다.

atest --include-subdir

--include-subdir 옵션이 없으면 Atest는 A 테스트만 실행합니다. --include-subdir 옵션이 있으면 Atest는 테스트 두 개 (A, B)를 실행합니다.

행 수준 주석 지원

행 수준 // 형식 주석을 추가하여 TEST_MAPPING 파일을 만들고 잇따른 설정에 대한 설명을 추가할 수 있습니다. ATest 및 Trade Federation 은 TEST_MAPPING을 주석 없이 유효한 JSON 형식으로 사전 처리합니다. JSON 파일을 깨끗하게 유지하기 위해 행 수준의 // 형식 주석만 지원됩니다.

예:

{
  // For presubmit test group.
  "presubmit": [
    {
      // Run test on module A.
      "name": "A"
    }
  ]
}