Contoh pengujian TF menyeluruh

Tutorial ini memandu Anda membuat konfigurasi pengujian Trade Federation (Tradefed atau TF) "hello world" dan memberikan pengantar langsung ke framework TF. Mulai dari lingkungan pengembangan, Anda akan membuat konfigurasi sederhana dan menambahkan fitur.

Tutorial ini menyajikan proses pengembangan pengujian sebagai serangkaian latihan, masing-masing terdiri dari beberapa langkah, yang menunjukkan cara mem-build dan secara bertahap meningkatkan konfigurasi Anda. Semua kode contoh yang Anda perlukan untuk menyelesaikan konfigurasi pengujian disediakan, dan judul setiap latihan dianotasi dengan huruf yang menjelaskan peran yang terlibat dalam langkah tersebut:

  • D untuk Developer
  • I untuk Integrator
  • R untuk Test Runner

Setelah menyelesaikan tutorial ini, Anda akan memiliki konfigurasi TF yang berfungsi dan memahami banyak konsep penting dalam framework TF.

Menyiapkan Federasi Perdagangan

Untuk mengetahui detail tentang cara menyiapkan lingkungan pengembangan TF, lihat Penyiapan Mesin. Bagian selanjutnya dari tutorial ini mengasumsikan bahwa Anda telah membuka shell yang telah diinisialisasi ke lingkungan TF.

Untuk memudahkan, tutorial ini mengilustrasikan penambahan konfigurasi dan class-nya ke library inti framework TF. Hal ini dapat diperluas untuk mengembangkan modul di luar hierarki sumber dengan mengompilasi JAR tradefed, lalu mengompilasi modul Anda terhadap JAR tersebut.

Membuat class pengujian (D)

Mari kita buat pengujian halo dunia yang hanya menampilkan pesan ke stdout. Pengujian tradefed umumnya mengimplementasikan antarmuka IRemoteTest. Berikut adalah implementasi untuk 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!");
    }
}

Simpan kode contoh ini ke <tree>/tools/tradefederation/core/src/com/android/tradefed/example/HelloWorldTest.java dan build ulang tradefed dari shell Anda:

m -jN

Perhatikan bahwa CLog.i dalam contoh di atas digunakan untuk mengarahkan output ke konsol. Informasi selengkapnya tentang logging di Trade Federation dijelaskan dalam Logging (D, I, R).

Jika build tidak berhasil, lihat Penyiapan Mesin untuk memastikan Anda tidak melewatkan langkah.

Membuat konfigurasi (I)

Pengujian Trade Federation dibuat dapat dieksekusi dengan membuat Konfigurasi, file XML yang menginstruksikan tradefed tentang pengujian (atau pengujian) yang akan dijalankan, serta modul lain yang akan dijalankan dan dalam urutan apa.

Mari kita buat Konfigurasi baru untuk HelloWorldTest (perhatikan nama class lengkap HelloWorldTest):

<configuration description="Runs the hello world test">
    <test class="com.android.tradefed.example.HelloWorldTest" />
</configuration>

Simpan data ini ke file helloworld.xml di mana saja di sistem file lokal Anda (misalnya, /tmp/helloworld.xml). TF akan mengurai file XML Konfigurasi (alias config), memuat class yang ditentukan menggunakan refleksi, membuat instance-nya, mentransmisikannya ke IRemoteTest, dan memanggil metode run-nya.

Menjalankan konfigurasi (R)

Dari shell, luncurkan konsol tradefed:

tradefed.sh

Pastikan perangkat terhubung ke mesin host dan terlihat oleh tradefed:

tf> list devices
Serial            State      Product   Variant   Build   Battery
004ad9880810a548  Available  mako      mako      JDQ39   100

Konfigurasi dapat dijalankan menggunakan perintah konsol run <config>. Coba:

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!

Anda akan melihat output "Halo, TF World!" di terminal.

Anda dapat mengonfirmasi bahwa perintah telah selesai dijalankan menggunakan list invocations atau l i di perintah konsol, dan perintah tersebut tidak akan mencetak apa pun. Jika perintah saat ini berjalan, perintah akan ditampilkan sebagai berikut:

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}'

Menambahkan konfigurasi ke classpath (D, I, R)

Untuk memudahkan deployment, Anda juga dapat memaketkan konfigurasi ke dalam JAR tradefed itu sendiri. Tradefed secara otomatis mengenali semua konfigurasi yang ditempatkan di folder config pada classpath.

Untuk mengilustrasikan, pindahkan file helloworld.xml ke library inti tradefed (<tree>/tools/tradefederation/core/res/config/example/helloworld.xml). Buat ulang tradefed, mulai ulang konsol tradefed, lalu minta tradefed untuk menampilkan daftar konfigurasi dari classpath:

tf> list configs
[…]
example/helloworld: Runs the hello world test

Anda kini dapat menjalankan konfigurasi helloworld menggunakan:

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!

Berinteraksi dengan perangkat (D, R)

Sejauh ini, HelloWorldTest kita tidak melakukan hal yang menarik. Spesialisasi Tradefed adalah menjalankan pengujian menggunakan perangkat Android, jadi mari kita tambahkan perangkat Android ke pengujian.

Pengujian dapat mendapatkan referensi ke perangkat Android menggunakan TestInformation, yang disediakan oleh framework saat metode IRemoteTest#run dipanggil.

Mari kita ubah pesan cetak HelloWorldTest untuk menampilkan nomor seri perangkat:

@Override
public void run(TestInformation testInfo, ITestInvocationListener listener) throws DeviceNotAvailableException {
    CLog.i("Hello, TF World! I have device " + testInfo.getDevice().getSerialNumber());
}

Sekarang, build ulang tradefed dan periksa daftar perangkat:

tradefed.sh
tf> list devices
Serial            State      Product   Variant   Build   Battery
004ad9880810a548  Available  mako      mako      JDQ39   100

Perhatikan nomor seri yang tercantum sebagai Tersedia; yaitu perangkat yang harus dialokasikan ke 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

Anda akan melihat pesan cetak baru yang menampilkan nomor seri perangkat.

Mengirim hasil pengujian (D)

IRemoteTest melaporkan hasil dengan memanggil metode pada instance ITestInvocationListener yang disediakan ke metode #run. Framework TF itu sendiri bertanggung jawab untuk melaporkan awal (melalui ITestInvocationListener#invocationStarted) dan akhir (melalui ITestInvocationListener#invocationEnded) setiap Pemanggilan.

Pengujian yang dijalankan adalah kumpulan pengujian yang logis. Untuk melaporkan hasil pengujian, IRemoteTest bertanggung jawab untuk melaporkan awal pengujian, awal dan akhir setiap pengujian, serta akhir pengujian.

Berikut tampilan implementasi HelloWorldTest dengan satu hasil pengujian yang gagal.

@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 menyertakan beberapa implementasi IRemoteTest yang dapat Anda gunakan kembali, bukan menulis sendiri dari awal. Misalnya, InstrumentationTest dapat menjalankan pengujian aplikasi Android dari jarak jauh di perangkat Android, mengurai hasil, dan meneruskan hasil tersebut ke ITestInvocationListener). Untuk mengetahui detailnya, lihat Jenis Pengujian.

Menyimpan hasil pengujian (I)

Implementasi pemroses pengujian default untuk konfigurasi TF adalah TextResultReporter, yang membuang hasil pemanggilan ke stdout. Untuk mengilustrasikannya, jalankan konfigurasi HelloWorldTest dari bagian sebelumnya:

./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

Untuk menyimpan hasil pemanggilan di tempat lain, seperti dalam file, tentukan penerapan ITestInvocationListener kustom menggunakan tag result_reporter dalam konfigurasi Anda.

TF juga menyertakan pemroses XmlResultReporter, yang menulis hasil pengujian ke file XML dalam format yang mirip dengan yang digunakan oleh penulis XML JUnit ant. Untuk menentukan result_reporter dalam konfigurasi, edit konfigurasi …/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>

Sekarang, build ulang tradefed dan jalankan kembali contoh 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

Perhatikan pesan log yang menyatakan bahwa file XML telah dibuat; file yang dihasilkan akan terlihat seperti ini:

<?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>

Anda juga dapat menulis pemroses pemanggilan kustom Anda sendiri—pemroses ini hanya perlu mengimplementasikan antarmuka ITestInvocationListener.

Tradefed mendukung beberapa pemroses pemanggilan, sehingga Anda dapat mengirim hasil pengujian ke beberapa tujuan independen. Untuk melakukannya, cukup tentukan beberapa tag <result_reporter> dalam konfigurasi Anda.

Fasilitas logging (D, I, R)

Fasilitas logging TF mencakup kemampuan untuk:

  1. Mengambil log dari perangkat (alias logcat perangkat)
  2. Merekam log dari framework Trade Federation yang berjalan di mesin host (alias log host)

Framework TF otomatis mengambil logcat dari perangkat yang dialokasikan dan mengirimkannya ke pemroses pemanggilan untuk diproses. XmlResultReporter kemudian menyimpan logcat perangkat yang diambil sebagai file.

Log host TF dilaporkan menggunakan wrapper CLog untuk class Log ddmlib. Mari kita konversikan panggilan System.out.println sebelumnya di HelloWorldTest menjadi panggilan CLog:

@Override
public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
    CLog.i("Hello, TF World! I have device %s", getDevice().getSerialNumber());

CLog menangani interpolasi string secara langsung, mirip dengan String.format. Saat mem-build ulang dan menjalankan ulang TF, Anda akan melihat pesan log di stdout:

tf> run example/helloworld
…
05-16 21:30:46 I/HelloWorldTest: Hello, TF World! I have device 004ad9880810a548
…

Secara default, tradefed menghasilkan pesan log host ke stdout. TF juga menyertakan implementasi log yang menulis pesan ke file: FileLogger. Untuk menambahkan logging file, tambahkan tag logger ke konfigurasi, yang menentukan nama class lengkap 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>

Sekarang, build ulang dan jalankan contoh helloworld lagi:

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
…

Pesan log menunjukkan jalur log host, yang saat dilihat, harus berisi pesan log HelloWorldTest Anda:

more /tmp/0/inv_6390011618174565918/host_log_4255420317120216614.txt

Contoh output:

…
05-16 21:38:21 I/HelloWorldTest: Hello, TF World! I have device 004ad9880810a548

Opsi penanganan (D, I, R)

Objek yang dimuat dari Konfigurasi TF (alias Objek konfigurasi) juga dapat menerima data dari argumen command line melalui penggunaan anotasi @Option.

Untuk berpartisipasi, class objek Konfigurasi menerapkan anotasi @Option ke kolom anggota dan memberinya nama unik. Hal ini memungkinkan nilai kolom anggota diisi melalui opsi command line (dan juga otomatis menambahkan opsi tersebut ke sistem bantuan konfigurasi).

Catatan: Tidak semua jenis kolom didukung. Untuk deskripsi jenis yang didukung, lihat OptionSetter.

Mari tambahkan @Option ke 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";

Selanjutnya, mari kita tambahkan pesan log untuk menampilkan nilai opsi di HelloWorldTest sehingga kita dapat menunjukkan bahwa opsi tersebut diterima dengan benar:

@Override
public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
    …
    CLog.logAndDisplay(LogLevel.INFO, "I received option '%s'", mMyOption);

Terakhir, build ulang TF dan jalankan helloworld; Anda akan melihat pesan log dengan nilai default my_option:

tf> run example/helloworld
…
05-24 18:30:05 I/HelloWorldTest: I received option 'thisisthedefault'

Meneruskan nilai dari command line

Teruskan nilai untuk my_option; Anda akan melihat my_option diisi dengan nilai tersebut:

tf> run example/helloworld --my_option foo
…
05-24 18:33:44 I/HelloWorldTest: I received option 'foo'

Konfigurasi TF juga menyertakan sistem bantuan, yang otomatis menampilkan teks bantuan untuk kolom @Option. Coba sekarang, dan Anda akan melihat teks bantuan untuk 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.

Perhatikan pesan tentang "hanya mencetak opsi yang penting". Untuk mengurangi kekacauan bantuan opsi, TF menggunakan atribut Option#importance untuk menentukan apakah akan menampilkan teks bantuan kolom @Option tertentu saat --help ditentukan. --help-all selalu menampilkan bantuan untuk semua kolom @Option, terlepas dari tingkat kepentingannya. Untuk mengetahui detailnya, lihat Option.Importance.

Meneruskan nilai dari konfigurasi

Anda juga dapat menentukan nilai Opsi dalam konfigurasi dengan menambahkan elemen <option name="" value="">. Uji menggunakan helloworld.xml:

<test class="com.android.tradefed.example.HelloWorldTest" >
    <option name="my_option" value="fromxml" />
</test>

Mem-build ulang dan menjalankan helloworld sekarang akan menghasilkan output ini:

05-24 20:38:25 I/HelloWorldTest: I received option 'fromxml'

Bantuan konfigurasi juga akan diperbarui untuk menunjukkan nilai default my_option:

tf> run example/helloworld --help
  test options:
    -m, --my_option      this is the option's help text Default: fromxml.

Objek konfigurasi lain yang disertakan dalam konfigurasi helloworld, seperti FileLogger, juga menerima opsi. Opsi --log-level-display menarik karena memfilter log yang muncul di stdout. Sebelumnya dalam tutorial ini, Anda mungkin telah melihat "Hello, TF World! Saya memiliki pesan log perangkat …' yang berhenti ditampilkan di stdout setelah kita beralih menggunakan FileLogger. Anda dapat meningkatkan panjang logging ke stdout dengan meneruskan argumen --log-level-display.

Coba sekarang, dan Anda akan melihat pesan log 'I have device' muncul kembali di stdout, selain dicatat ke dalam file:

tf> run example/helloworld --log-level-display info
…
05-24 18:53:50 I/HelloWorldTest: Hello, TF World! I have device 004ad9880810a548

Sekian.

Sebagai pengingat, jika Anda mengalami kesulitan, kode sumber Trade Federation memiliki banyak informasi berguna yang tidak ditampilkan dalam dokumentasi. Jika semua cara lain gagal, coba ajukan pertanyaan di android-platform Google Grup, dengan "Trade Federation" di subjek pesan.