Testowanie mapowania

Ten artykuł zawiera krótkie wprowadzenie do mapowania testów oraz wyjaśnienie, jak rozpocząć konfigurowanie testów w projektach typu Open Source w Androidzie (AOSP).

Informacje o mapowaniu testów

Mapowanie testów to podejście oparte na Gerricie, które pozwala deweloperom tworzyć reguły testów przed przesłaniem i po przesłaniu bezpośrednio w drzewie źródłowym Androida, a także pozostawiać infrastrukturze testowej decyzje dotyczące gałęzi i urządzeń, które mają być testowane. Definicje testów mapowania to pliki JSON o nazwie TEST_MAPPING, które możesz umieścić w dowolnym katalogu źródłowym.

Atest może używać plików TEST_MAPPING do przeprowadzania testów przed przesłaniem w powiązanych katalogach. Dzięki mapowaniu testów możesz dodać ten sam zestaw testów do weryfikacji przed przesłaniem, wprowadzając minimalne zmiany w drzewie źródłowym Androida.

Zapoznaj się z tymi przykładami:

Mapowanie testów polega na korzystaniu z testów Trade Federation (TF) do wykonywania testów i raportowania wyników.

Definiowanie grup testowych

Testowanie grup mapowania za pomocą grupy testowej. Nazwa grupy testów może być dowolnym ciągiem znaków. Na przykład presubmit może być nazwą grupy testów, które należy wykonać podczas sprawdzania zmian. Testy po przesłaniu mogą służyć do sprawdzania kompilacji po złączeniu zmian.

Reguły skryptu kompilacji pakietu

Aby narzędzie testowe Trade Federation mogło uruchamiać moduły testowe danej kompilacji, moduły te muszą mieć ustawioną wartość test_suites dla Soong lub LOCAL_COMPATIBILITY_SUITE dla Make w ramach jednego z tych pakietów:

  • general-tests służy do testów, które nie zależą od funkcji dostępnych na konkretnym urządzeniu (np. sprzętu konkretnego producenta, którego nie ma większość urządzeń). Większość testów powinna być zawarta w pakiecie general-tests, nawet jeśli dotyczą one konkretnego ABI, liczby bitów lub funkcji sprzętowych, takich jak HWASan (dla każdego ABI jest osobny obiekt docelowy test_suites), a także nawet jeśli muszą być wykonywane na urządzeniu.
  • device-tests służy do testów, które zależą od możliwości urządzenia. Zwykle te testy znajdują się w sekcji vendor/. Dla urządzenia odnosi się tylko do funkcji, które są unikalne dla urządzenia, dlatego dotyczy to zarówno testów JUnit, jak i testów GTest (które zwykle powinny być oznaczone jako general-tests, nawet jeśli są specyficzne dla ABI).

Przykłady:

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

Konfigurowanie testów do uruchomienia w pakiecie testów

Aby test mógł być wykonywany w ramach zestawu testów:

  • Nie może być dostawcy kompilacji.
  • Po zakończeniu testu musisz wyczyścić system, na przykład usuwając tymczasowe pliki utworzone podczas testu.
  • Musisz zmienić ustawienia systemowe na domyślne lub pierwotne wartości.
  • Nie należy zakładać, że urządzenie jest w określonym stanie, na przykład gotowe do rootowania. Większość testów nie wymaga uprawnień roota. Jeśli test wymaga uprawnień root, należy to określić za pomocą parametru RootTargetPreparerAndroidTest.xml, jak w tym przykładzie:

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

Tworzenie testowych plików mapowania

W przypadku katalogu wymagającego testowania dodaj plik JSON TEST_MAPPING podobny do tego. Te reguły zapewniają, że testy są uruchamiane w ramach weryfikacji przed przesłaniem, gdy w tym katalogu lub dowolnym z jego podkatalogów zostaną zmienione jakiekolwiek pliki.

Postępuj zgodnie z przykładem

Oto przykładowy plik TEST_MAPPING (jest on w formacie JSON, ale obsługuje komentarze):

{
  "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"
    }
  ]
}

Ustawianie atrybutów

W przykładzie presubmitpostsubmit to nazwy poszczególnych grup testowych. Więcej informacji o grupach testów znajdziesz w artykule Definiowanie grup testów.

W wartości atrybutu name możesz podać nazwę modułu testowego lub nazwę testu integracji z Federacją Handlową (ścieżka do zasobu do pliku XML testu, np. uiautomator/uiautomator-demo). Pamiętaj, że w polu name nie możesz użyć klasy name ani metody testu name. Aby zawęzić zakres testów do wykonania, użyj opcji takich jak include-filter. Zobacz include-filter przykładowe użycie.

Ustawienie host testu wskazuje, czy jest to test bez urządzenia działający na hoście. Wartość domyślna to false, co oznacza, że test wymaga użycia urządzenia. Obsługiwane typy testów to HostGTest w przypadku binarek GTest i HostTest w przypadku testów JUnit.

Atrybut file_patterns umożliwia ustawienie listy ciągów wyrażeń regularnych do dopasowywania ścieżki względnej dowolnego pliku kodu źródłowego (względnie katalogu zawierającego plik TEST_MAPPING). W przykładzie test CtsWindowManagerDeviceTestCases jest wykonywany przed przesłaniem tylko wtedy, gdy plik Java zaczyna się od Window lub Activity, który znajduje się w tym samym katalogu co plik TEST_MAPPING lub w jednym z jego podkatalogów. Znaki ukośnikowe (\) muszą być ujęte w znaki ucieczki, ponieważ znajdują się w pliku JSON.

Atrybut imports umożliwia uwzględnianie testów w innych plikach TEST_MAPPING bez kopiowania treści. Do pliku importowanego ścieżki dołączone są też pliki TEST_MAPPING z folderów nadrzędnych. Mapowanie testów umożliwia zagnieżdżone importy, co oznacza, że 2 pliki TEST_MAPPING mogą się nawzajem importować, a mapowanie testów może łączyć zawarte w nich testy.

Atrybut options zawiera dodatkowe opcje wiersza poleceń Tradefed.

Aby zobaczyć pełną listę dostępnych opcji dla danego testu, wykonaj:

tradefed.sh run commandAndExit [test_module] --help

Więcej informacji o tym, jak działają opcje, znajdziesz w artykule Opracowywanie opcji w Tradefed.

Przeprowadzanie testów za pomocą Atest

Aby uruchomić reguły testowania przed przesłaniem lokalnie:

  1. Przejdź do katalogu zawierającego plik TEST_MAPPING.
  2. Uruchom polecenie:

    atest
    

Uruchomione są wszystkie testy przed przesłaniem skonfigurowane w plikach TEST_MAPPING w bieżącym katalogu i jego katalogach nadrzędnych. Atest znajduje i uruchamia 2 testy przed przesłaniem (A i B).

Jest to najprostszy sposób na uruchomienie testów przed przesłaniem w plikach TEST_MAPPING w bieżącym katalogu roboczym (CWD) i katalogach nadrzędnych. Atest znajduje i używa pliku TEST_MAPPING w katalogu CWD i wszystkich jego katalogach nadrzędnych.

Struktura kodu źródłowego

Ten przykład pokazuje, jak skonfigurować pliki TEST_MAPPING w drzewie źródeł:

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

Treść src/TEST_MAPPING:

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

Treść src/project_1/TEST_MAPPING:

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

Treść src/project_2/TEST_MAPPING:

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

Określanie katalogów docelowych

Możesz podać katalog docelowy, aby uruchomić testy w plikach TEST_MAPPING w tym katalogu. To polecenie uruchamia 2 testy (A, B):

atest --test-mapping src/project_1

Przeprowadzanie reguł testowych po przesłaniu

Możesz też użyć tego polecenia, aby uruchomić reguły testowe po przesłaniu zdefiniowane w TEST_MAPPINGsrc_path (domyślnie bieżący katalog) i jego katalogach nadrzędnych:

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

Uruchamianie tylko testów, które nie wymagają urządzenia

Możesz użyć opcji --host w Atest, aby uruchomić tylko te testy skonfigurowane w przypadku hosta, które nie wymagają urządzenia. Bez tej opcji Atest uruchamia oba testy – te, które wymagają urządzenia, oraz te, które są wykonywane na hoście, który nie wymaga urządzenia. Testy są przeprowadzane w 2 oddzielnych zestawach:

atest [--test-mapping] --host

Identyfikowanie grup testowych

Grupy testów możesz określić w komendach Atest. Podane niżej polecenie uruchamia wszystkie testy postsubmit dotyczące plików w katalogu src/project_1, który zawiera tylko jeden test (C).

Możesz też użyć :all, aby uruchomić wszystkie testy bez względu na grupę. To polecenie uruchamia 4 testy (A, B, C, X):

atest --test-mapping src/project_1:all

Uwzględnij podkatalogi

Domyślnie uruchamianie testów w TEST_MAPPING za pomocą Atest powoduje uruchomienie tylko testów przed przesłaniem skonfigurowanych w pliku TEST_MAPPING w katalogu CWD (lub katalogu podrzędnym) i jego folderach nadrzędnych. Jeśli chcesz uruchomić testy we wszystkich plikach TEST_MAPPING w podfolderach, użyj opcji --include-subdir, aby wymusić uwzględnienie tych testów przez Atest.

atest --include-subdir

Bez opcji --include-subdir Atest wykonuje tylko test A. W przypadku opcji --include-subdir Atest przeprowadza 2 testy (A i B).

Komentarze na poziomie wiersza

Możesz dodać komentarz w formacie // na poziomie wiersza, aby uzupełnić plik TEST_MAPPING o opis ustawień, które występują później. ATest i Federacja handlowa przetwarzają TEST_MAPPING do prawidłowego formatu JSON bez komentarzy. Aby plik JSON był przejrzysty, obsługiwany jest tylko komentarz w formacie // na poziomie wiersza.

Przykład:

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