Ten samouczek przeprowadzi Cię przez proces tworzenia konfiguracji testowej Federacji Handlowej (Tradefed lub TF) „witaj, świecie” i zapewni praktyczne wprowadzenie do frameworka TF. Zaczynając od środowiska programistycznego, utworzysz prostą konfigurację i dodasz funkcje.
W samouczku przedstawiono proces tworzenia testów w postaci zestawu ćwiczeń, z których każde składa się z kilku kroków, które pokazują, jak zbudować i stopniowo udoskonalać konfigurację. Dostarczono cały przykładowy kod potrzebny do ukończenia konfiguracji testu, a tytuł każdego ćwiczenia jest opatrzony literą opisującą role zaangażowane w tym kroku:
- D dla programisty
- Ja za Integratora
- R jak biegacz testowy
Po ukończeniu samouczka będziesz mieć działającą konfigurację TF i zrozumiesz wiele ważnych koncepcji w środowisku TF.
Załóż Federację Handlową
Aby uzyskać szczegółowe informacje na temat konfigurowania środowiska programistycznego TF, zobacz Konfiguracja maszyny . W pozostałej części tego samouczka założono, że masz otwartą powłokę, która została zainicjowana w środowisku TF.
Dla uproszczenia ten samouczek ilustruje dodawanie konfiguracji i jej klas do podstawowej biblioteki platformy TF. Można to rozszerzyć na tworzenie modułów poza drzewem źródłowym, kompilując dostarczony plik JAR, a następnie kompilując moduły na podstawie tego pliku JAR.
Utwórz klasę testową (D)
Stwórzmy test hello world, który po prostu zrzuci wiadomość na standardowe wyjście. Test handlowy zazwyczaj implementuje interfejs IRemoteTest . Oto implementacja HelloWorldTest:
package com.android.tradefed.example; import com.android.tradefed.device.DeviceNotAvailableException; import com.android.tradefed.invoker.TestInformation; import com.android.tradefed.log.LogUtil.CLog; import com.android.tradefed.result.ITestInvocationListener; import com.android.tradefed.testtype.IRemoteTest; public class HelloWorldTest implements IRemoteTest { @Override public void run(TestInformation testInfo, ITestInvocationListener listener) throws DeviceNotAvailableException { CLog.i("Hello, TF World!"); } }
Zapisz ten przykładowy kod w <tree>/tools/tradefederation/core/src/com/android/tradefed/example/HelloWorldTest.java
i odbuduj Tradefed ze swojej powłoki:
m -jN
Zauważ, że CLog.i
w powyższym przykładzie jest używany do kierowania danych wyjściowych do konsoli. Więcej informacji na temat logowania do Federacji Handlowej opisano w rozdziale Logowanie (D, I, R) .
Jeśli kompilacja się nie powiedzie, skonsultuj się z konfiguracją maszyny , aby upewnić się, że nie pominąłeś żadnego kroku.
Utwórz konfigurację (I)
Testy Federacji Handlowej stają się wykonywalne poprzez utworzenie pliku konfiguracyjnego XML, który instruuje firmę handlującą, który test (lub testy) ma uruchomić, a także które inne moduły mają zostać wykonane i w jakiej kolejności.
Stwórzmy nową konfigurację dla naszego HelloWorldTest (zanotuj pełną nazwę klasy HelloWorldTest):
<configuration description="Runs the hello world test"> <test class="com.android.tradefed.example.HelloWorldTest" /> </configuration>
Zapisz te dane w pliku helloworld.xml
w dowolnym miejscu lokalnego systemu plików (np. /tmp/helloworld.xml
). TF przeanalizuje plik konfiguracyjny XML (inaczej config ), załaduje określoną klasę za pomocą odbicia, utworzy jej instancję, przerzuci ją na IRemoteTest
i wywoła jej metodę run
.
Uruchom konfigurację (R)
Z poziomu powłoki uruchom wymienioną konsolę:
tradefed.sh
Upewnij się, że urządzenie jest podłączone do komputera hosta i jest widoczne dla traderów:
tf> list devices Serial State Product Variant Build Battery 004ad9880810a548 Available mako mako JDQ39 100
Konfiguracje można wykonać za pomocą polecenia konsoli run <config>
. Próbować:
tf> run /tmp/helloworld.xml 05-12 13:19:36 I/TestInvocation: Starting invocation for target stub on build 0 on device 004ad9880810a548 Hello, TF World!
Powinieneś zobaczyć „Witaj, świecie TF!” wyjście na terminal.
Możesz potwierdzić, że polecenie zostało wykonane, używając list invocations
lub li
w wierszu poleceń konsoli; polecenie nie powinno nic wyświetlić. Jeśli polecenia są aktualnie uruchomione, są one wyświetlane w następujący sposób:
tf >l i Command Id Exec Time Device State 10 0m:00 [876X00GNG] running stub on build(s) 'BuildInfo{bid=0, target=stub, serial=876X00GNG}'
Dodaj konfigurację do ścieżki klas (D, I, R)
Dla wygody wdrożenia możesz także spakować konfiguracje do samych plików JAR. Tradefed automatycznie rozpoznaje wszystkie konfiguracje umieszczone w folderach konfiguracyjnych w ścieżce klas.
Aby to zilustrować, przenieś plik helloworld.xml
do podstawowej biblioteki Tradefed ( <tree>/tools/tradefederation/core/res/config/example/helloworld.xml
). Odbuduj Tradefed, zrestartuj konsolę Tradefed, a następnie poproś Tradefed o wyświetlenie listy konfiguracji ze ścieżki klas:
tf> list configs […] example/helloworld: Runs the hello world test
Możesz teraz uruchomić konfigurację helloworld za pomocą:
tf> run example/helloworld 05-12 13:21:21 I/TestInvocation: Starting invocation for target stub on build 0 on device 004ad9880810a548 Hello, TF World!
Interakcja z urządzeniem (D, R)
Jak na razie nasz HelloWorldTest nie robi nic interesującego. Specjalnością Tradefed jest przeprowadzanie testów na urządzeniach z Androidem, więc dodajmy do testu urządzenie z Androidem.
Testy mogą uzyskać odwołanie do urządzenia z systemem Android za pomocą TestInformation
dostarczonego przez platformę po wywołaniu metody IRemoteTest#run
.
Zmodyfikujmy komunikat wydruku HelloWorldTest, aby wyświetlał numer seryjny urządzenia:
@Override public void run(TestInformation testInfo, ITestInvocationListener listener) throws DeviceNotAvailableException { CLog.i("Hello, TF World! I have device " + testInfo.getDevice().getSerialNumber()); }
Teraz odbuduj Tradefed i sprawdź listę urządzeń:
tradefed.sh
tf> list devices Serial State Product Variant Build Battery 004ad9880810a548 Available mako mako JDQ39 100
Zanotuj numer seryjny wymieniony jako Dostępny ; to jest urządzenie, które powinno zostać przydzielone do HelloWorld:
tf> run example/helloworld 05-12 13:26:18 I/TestInvocation: Starting invocation for target stub on build 0 on device 004ad9880810a548 Hello, TF World! I have device 004ad9880810a548
Powinieneś zobaczyć nowy komunikat drukowania zawierający numer seryjny urządzenia.
Wyślij wyniki testu (D)
IRemoteTest
raportuje wyniki, wywołując metody w instancji ITestInvocationListener dostarczonej do metody #run
. Sama struktura TF jest odpowiedzialna za raportowanie początku (za pośrednictwem ITestInvocationListener#invocationStarted ) i zakończenia (za pośrednictwem ITestInvocationListener#invocationEnded ) każdego wywołania.
Przebieg testu to logiczny zbiór testów. Aby zgłosić wyniki testu, IRemoteTest
jest odpowiedzialny za raportowanie rozpoczęcia przebiegu testu, początku i końca każdego testu oraz zakończenia przebiegu testu.
Oto jak może wyglądać implementacja HelloWorldTest w przypadku pojedynczego wyniku testu zakończonego niepowodzeniem.
@Override public void run(TestInformation testInfo, ITestInvocationListener listener) throws DeviceNotAvailableException { CLog.i("Hello, TF World! I have device " + testInfo.getDevice().getSerialNumber()); TestDescription testId = new TestDescription("com.example.TestClassName", "sampleTest"); listener.testRunStarted("helloworldrun", 1); listener.testStarted(testId); listener.testFailed(testId, "oh noes, test failed"); listener.testEnded(testId, Collections.emptyMap()); listener.testRunEnded(0, Collections.emptyMap()); }
TF zawiera kilka implementacji IRemoteTest
, których możesz użyć ponownie, zamiast pisać własne od zera. Na przykład InstrumentationTest może zdalnie uruchamiać testy aplikacji dla systemu Android na urządzeniu z systemem Android, analizować wyniki i przekazywać je do ITestInvocationListener
). Aby uzyskać szczegółowe informacje, zobacz Typy testów .
Przechowuj wyniki testów (I)
Domyślną implementacją odbiornika testowego dla konfiguracji TF jest TextResultReporter , która zrzuca wyniki wywołania na standardowe wyjście. Aby to zilustrować, uruchom konfigurację HelloWorldTest z poprzedniej sekcji:
./tradefed.sh
tf> run example/helloworld 04-29 18:25:55 I/TestInvocation: Invocation was started with cmd: /tmp/helloworld.xml 04-29 18:25:55 I/TestInvocation: Starting invocation for 'stub' with '[ BuildInfo{bid=0, target=stub, serial=876X00GNG} on device '876X00GNG'] 04-29 18:25:55 I/HelloWorldTest: Hello, TF World! I have device 876X00GNG 04-29 18:25:55 I/InvocationToJUnitResultForwarder: Running helloworldrun: 1 tests 04-29 18:25:55 W/InvocationToJUnitResultForwarder: Test com.example.TestClassName#sampleTest failed with stack: oh noes, test failed 04-29 18:25:55 I/InvocationToJUnitResultForwarder: Run ended in 0 ms
Aby zapisać wyniki wywołania w innym miejscu, na przykład w pliku, określ niestandardową implementację ITestInvocationListener
, używając result_reporter
w konfiguracji.
TF zawiera także odbiornik XmlResultReporter , który zapisuje wyniki testów do pliku XML w formacie podobnym do używanego przez moduł zapisujący XML Ant JUnit. Aby określić report_reporter w konfiguracji, edytuj konfigurację …/res/config/example/helloworld.xml
:
<configuration description="Runs the hello world test"> <test class="com.android.tradefed.example.HelloWorldTest" /> <result_reporter class="com.android.tradefed.result.XmlResultReporter" /> </configuration>
Teraz odbuduj Tradefed i ponownie uruchom próbkę hello world:
tf> run example/helloworld 05-16 21:07:07 I/TestInvocation: Starting invocation for target stub on build 0 on device 004ad9880810a548 Hello, TF World! I have device 004ad9880810a548 05-16 21:07:07 I/XmlResultReporter: Saved device_logcat log to /tmp/0/inv_2991649128735283633/device_logcat_6999997036887173857.txt 05-16 21:07:07 I/XmlResultReporter: Saved host_log log to /tmp/0/inv_2991649128735283633/host_log_6307746032218561704.txt 05-16 21:07:07 I/XmlResultReporter: XML test result file generated at /tmp/0/inv_2991649128735283633/test_result_536358148261684076.xml. Total tests 1, Failed 1, Error 0
Zwróć uwagę na komunikat dziennika informujący, że wygenerowano plik XML; wygenerowany plik powinien wyglądać następująco:
<?xml version='1.0' encoding='UTF-8' ?> <testsuite name="stub" tests="1" failures="1" errors="0" time="9" timestamp="2011-05-17T04:07:07" hostname="localhost"> <properties /> <testcase name="sampleTest" classname="com.example.TestClassName" time="0"> <failure>oh noes, test failed </failure> </testcase> </testsuite>
Możesz także napisać własne niestandardowe odbiorniki wywołań — wystarczy, że zaimplementują interfejs ITestInvocationListener .
Tradefed obsługuje wiele odbiorników wywołań, dzięki czemu możesz wysyłać wyniki testów do wielu niezależnych miejsc docelowych. Aby to zrobić, po prostu określ wiele tagów <result_reporter>
w swojej konfiguracji.
Urządzenia do pozyskiwania drewna (D, I, R)
Możliwości logowania TF obejmują możliwość:
- Przechwytuj dzienniki z urządzenia (inaczej logcat urządzenia)
- Rejestruj dzienniki z platformy Federacji Handlowej działającej na komputerze hosta (inaczej dziennik hosta)
Struktura TF automatycznie przechwytuje logcat z przydzielonego urządzenia i wysyła go do słuchacza wywołań w celu przetworzenia. Następnie XmlResultReporter
zapisuje przechwycony logcat urządzenia jako plik.
Dzienniki hosta TF są raportowane przy użyciu opakowania CLog dla klasy ddmlib Log. Przekonwertujmy poprzednie wywołanie System.out.println
w HelloWorldTest na wywołanie CLog
:
@Override public void run(ITestInvocationListener listener) throws DeviceNotAvailableException { CLog.i("Hello, TF World! I have device %s", getDevice().getSerialNumber());
CLog
obsługuje bezpośrednio interpolację ciągów, podobnie jak String.format
. Kiedy przebudujesz i ponownie uruchomisz TF, powinieneś zobaczyć komunikat dziennika na stdout:
tf> run example/helloworld … 05-16 21:30:46 I/HelloWorldTest: Hello, TF World! I have device 004ad9880810a548 …
Domyślnie Tradefed wysyła komunikaty dziennika hosta na standardowe wyjście . TF zawiera również implementację dziennika, która zapisuje komunikaty do pliku: FileLogger . Aby dodać rejestrowanie plików, dodaj do konfiguracji znacznik logger
, podając pełną nazwę klasy FileLogger
:
<configuration description="Runs the hello world test"> <test class="com.android.tradefed.example.HelloWorldTest" /> <result_reporter class="com.android.tradefed.result.XmlResultReporter" /> <logger class="com.android.tradefed.log.FileLogger" /> </configuration>
Teraz przebuduj i ponownie uruchom przykład helloworld:
tf >run example/helloworld … 05-16 21:38:21 I/XmlResultReporter: Saved device_logcat log to /tmp/0/inv_6390011618174565918/device_logcat_1302097394309452308.txt 05-16 21:38:21 I/XmlResultReporter: Saved host_log log to /tmp/0/inv_6390011618174565918/host_log_4255420317120216614.txt …
Komunikat dziennika wskazuje ścieżkę dziennika hosta, który po przejrzeniu powinien zawierać komunikat dziennika HelloWorldTest:
more /tmp/0/inv_6390011618174565918/host_log_4255420317120216614.txt
Przykładowe wyjście:
… 05-16 21:38:21 I/HelloWorldTest: Hello, TF World! I have device 004ad9880810a548
Opcje obsługi (D, I, R)
Obiekty ładowane z konfiguracji TF (inaczej obiekty konfiguracyjne ) mogą również odbierać dane z argumentów wiersza poleceń poprzez użycie adnotacji @Option
.
Aby wziąć udział, klasa obiektu Configuration stosuje adnotację @Option
do pola członkowskiego i nadaje mu unikalną nazwę. Umożliwia to wypełnienie wartości pola elementu za pomocą opcji wiersza poleceń (a także automatycznie dodaje tę opcję do systemu pomocy konfiguracyjnej).
Uwaga: nie wszystkie typy pól są obsługiwane. Aby uzyskać opis obsługiwanych typów, zobacz OptionSetter .
Dodajmy @Option
do HelloWorldTest:
@Option(name="my_option", shortName='m', description="this is the option's help text", // always display this option in the default help text importance=Importance.ALWAYS) private String mMyOption = "thisisthedefault";
Następnie dodajmy komunikat dziennika, aby wyświetlić wartość opcji w HelloWorldTest, abyśmy mogli wykazać, że została poprawnie odebrana:
@Override public void run(ITestInvocationListener listener) throws DeviceNotAvailableException { … CLog.logAndDisplay(LogLevel.INFO, "I received option '%s'", mMyOption);
Na koniec odbuduj TF i uruchom helloworld; powinieneś zobaczyć komunikat dziennika z domyślną wartością my_option
:
tf> run example/helloworld … 05-24 18:30:05 I/HelloWorldTest: I received option 'thisisthedefault'
Przekaż wartości z wiersza poleceń
Przekaż wartość my_option
; powinieneś zobaczyć my_option
wypełnioną tą wartością:
tf> run example/helloworld --my_option foo … 05-24 18:33:44 I/HelloWorldTest: I received option 'foo'
Konfiguracje TF zawierają także system pomocy, który automatycznie wyświetla tekst pomocy dla pól @Option
. Wypróbuj teraz, a powinieneś zobaczyć tekst pomocy dla my_option
:
tf> run example/helloworld --help Printing help for only the important options. To see help for all options, use the --help-all flag cmd_options options: --[no-]help display the help text for the most important/critical options. Default: false. --[no-]help-all display the full help text for all options. Default: false. --[no-]loop keep running continuously. Default: false. test options: -m, --my_option this is the option's help text Default: thisisthedefault. 'file' logger options: --log-level-display the minimum log level to display on stdout. Must be one of verbose, debug, info, warn, error, assert. Default: error.
Zwróć uwagę na komunikat „drukowanie tylko ważnych opcji”. Aby zmniejszyć bałagan w pomocy dotyczącej opcji, TF używa atrybutu Option#importance
w celu określenia, czy wyświetlać tekst pomocy konkretnego pola @Option
, gdy podano --help
. --help-all
zawsze pokazuje pomoc dla wszystkich pól @Option
, niezależnie od ich ważności. Aby uzyskać szczegółowe informacje, zobacz Opcja.Ważność .
Przekaż wartości z konfiguracji
Możesz także określić wartość opcji w konfiguracji, dodając element <option name="" value="">
. Przetestuj to za pomocą helloworld.xml
:
<test class="com.android.tradefed.example.HelloWorldTest" > <option name="my_option" value="fromxml" /> </test>
Ponowne zbudowanie i uruchomienie helloworld powinno teraz dać następujący wynik:
05-24 20:38:25 I/HelloWorldTest: I received option 'fromxml'
Pomoc konfiguracyjna powinna również zostać zaktualizowana, aby wskazać domyślną wartość my_option
:
tf> run example/helloworld --help test options: -m, --my_option this is the option's help text Default: fromxml.
Inne obiekty konfiguracyjne zawarte w konfiguracji helloworld, takie jak FileLogger
, również akceptują opcje. Opcja --log-level-display
jest interesująca, ponieważ filtruje logi wyświetlane na stdout. Wcześniej w tym samouczku być może zauważyłeś, że komunikat dziennika „Witaj, TF World! Mam urządzenie…” przestał być wyświetlany na stdout po przejściu na FileLogger
. Możesz zwiększyć szczegółowość logowania na standardowe wyjście, przekazując --log-level-display
arg --log-level-display
.
Spróbuj tego teraz, a poza zalogowaniem do pliku powinieneś ponownie zobaczyć komunikat dziennika „Mam urządzenie” na standardowym wyjściu:
tf> run example/helloworld --log-level-display info … 05-24 18:53:50 I/HelloWorldTest: Hello, TF World! I have device 004ad9880810a548
To wszystko, ludzie!
Przypominamy, że jeśli na czymś utkniesz, kod źródłowy Federacji Handlowej zawiera wiele przydatnych informacji, które nie są ujawnione w dokumentacji. Jeśli wszystko inne zawiedzie, spróbuj zapytać w Grupie dyskusyjnej Google na platformie Android , w temacie wiadomości wpisując „Federacja handlowa”.