Uçtan uca TF testi örneği

Bu eğitim, "Merhaba dünya" Trade Federation (Tradefed veya TF) test yapılandırması oluşturma konusunda size yol gösterir ve TF çerçevesine uygulamalı bir giriş sunar. Geliştirme ortamından başlayarak basit bir yapılandırma oluşturup özellikler ekleyeceksiniz.

Eğitim, test geliştirme sürecini bir dizi alıştırma olarak sunar. Her alıştırma, yapılandırmanızı nasıl oluşturacağınızı ve kademeli olarak nasıl hassaslaştıracağınızı gösteren birkaç adımdan oluşur. Test yapılandırmasını tamamlamak için ihtiyacınız olan tüm örnek kod sağlanmıştır ve her alıştırmanın başlığı, ilgili adımda yer alan rolleri açıklayan bir harfle ek açıklamaya sahiptir:

  • Geliştirici için D
  • Entegre eden için I
  • Test çalıştırıcı için R

Eğitimi tamamladıktan sonra çalışan bir TF yapılandırmanız olur ve TF çerçevesindeki birçok önemli kavramı anlarsınız.

Ticaret Federasyonu'nu ayarlama

TF geliştirme ortamını ayarlamayla ilgili ayrıntılar için Makine Kurulumu başlıklı makaleyi inceleyin. Bu eğitimdeki diğer bölümlerde, TF ortamında başlatılmış bir kabuğunuz olduğu varsayılmaktadır.

Bu eğitimde, basitlik açısından bir yapılandırmanın ve sınıflarının TF çerçevesi ana kitaplığına eklenmesi gösterilmektedir. Bu, tradefed JAR'ı derleyip ardından modüllerinizi bu JAR'a göre derleyerek kaynak ağacının dışında modül geliştirmeye kadar genişletilebilir.

Test sınıfı oluşturma (D)

Yalnızca stdout'a bir mesaj yayan bir Merhaba Dünya testi oluşturalım. Tradefed testi genellikle IRemoteTest arayüzünü uygular. HelloWorldTest için bir uygulama aşağıda verilmiştir:

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!");
    }
}

Bu örnek kodu <tree>/tools/tradefederation/core/src/com/android/tradefed/example/HelloWorldTest.java içine kaydedin ve kabuğunuzdan tradefed'i yeniden oluşturun:

m -jN

Yukarıdaki örnekte CLog.i değerinin çıkışı konsola yönlendirmek için kullanıldığını unutmayın. Trade Federation'a giriş yapma hakkında daha fazla bilgi Günlük kaydı (D, I, R) bölümünde açıklanmıştır.

Derleme başarılı olmazsa bir adımı atlamadığınızdan emin olmak için Makine Kurulumu'na bakın.

Yapılandırma oluşturma (I)

Trade Federation testleri, tradefed'e hangi testin (veya testlerin) çalıştırılacağının yanı sıra hangi diğer modüllerin ve hangi sırayla çalıştırılacağını belirten bir yapılandırma (XML dosyası) oluşturularak çalıştırılabilir hale getirilir.

HelloWorldTest için yeni bir yapılandırma oluşturalım (HelloWorldTest sınıfının tam adını not edin):

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

Bu verileri yerel dosya sisteminizin herhangi bir yerindeki bir helloworld.xml dosyasına kaydedin (ör. /tmp/helloworld.xml). TF, yapılandırma XML dosyasını (diğer adıyla config) ayrıştırır, yansımayı kullanarak belirtilen sınıfı yükler, sınıfı örneklendirir, IRemoteTest olarak yayınlar ve run yöntemini çağırır.

Yapılandırmayı çalıştırma (R)

Kabuğunuzdan tradefed konsolunu başlatın:

tradefed.sh

Bir cihazın ana makineye bağlı olduğundan ve tradefed tarafından görülebildiğinden emin olun:

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

Yapılandırmalar, run <config>console komutu kullanılarak yürütülebilir. Bunu deneyin:

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!

Terminalde "Hello, TF World!" çıkışını görürsünüz.

Konsolda list invocations veya l i kullanarak bir komutun çalıştırıldığını onaylayabilirsiniz. Bu durumda hiçbir şey yazdırılmaz. Şu anda çalışan komutlar aşağıdaki gibi gösterilir:

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

Yapılandırmayı sınıf yoluna ekleyin (D, I, R)

Dağıtım kolaylığı için yapılandırmaları tradefed JAR'larına da ekleyebilirsiniz. Tradefed, sınıf yolu klasörlerindeki config klasörlerine yerleştirilen tüm yapılandırmaları otomatik olarak tanır.

Bunu açıklamak için helloworld.xml dosyasını tradefed temel kitaplığına (<tree>/tools/tradefederation/core/res/config/example/helloworld.xml) taşıyın. tradefed'i yeniden oluşturun, tradefed konsolunu yeniden başlatın ve ardından tradefed'den sınıf yolu klasöründeki yapılandırmaların listesini göstermesini isteyin:

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

Artık helloworld yapılandırmasını şunu kullanarak çalıştırabilirsiniz:

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!

Bir cihazla etkileşimde bulunma (D, R)

HelloWorldTest'imiz şimdilik ilginç bir şey yapmıyor. Tradefed'in uzmanlık alanı Android cihazları kullanarak test yürütmektir. Bu nedenle teste bir Android cihaz ekleyelim.

Testler, IRemoteTest#run yöntemi çağrıldığında çerçeve tarafından sağlanan TestInformation öğesini kullanarak bir Android cihaz referansı alabilir.

HelloWorldTest baskı mesajını, cihazın seri numarasını gösterecek şekilde değiştirelim:

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

Ardından tradefed'i yeniden oluşturun ve cihaz listesini kontrol edin:

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

Kullanılabilir olarak listelenen seri numarasını not edin. Bu, HelloWorld'a atanması gereken cihazdır:

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

Cihazın seri numarasını gösteren yeni baskı mesajını görürsünüz.

Test sonuçlarını gönder (D)

IRemoteTest, #run yöntemine sağlanan ITestInvocationListener örneğinde yöntemler çağırarak sonuçları raporlar. Her çağrının başlangıcını (ITestInvocationListener#invocationStarted aracılığıyla) ve sonunu (ITestInvocationListener#invocationEnded aracılığıyla) bildirmekten TF çerçevesi sorumludur.

Test çalıştırma, mantıksal bir test koleksiyonudur. Test sonuçlarını bildirmek için IRemoteTest, test çalıştırmasının başlangıcını, her testin başlangıç ve bitiş zamanını ve test çalıştırmasının bitişini bildirmekten sorumludur.

Tek bir başarısız test sonucuyla HelloWorldTest uygulamasının nasıl görünebileceği aşağıda gösterilmektedir.

@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, sıfırdan kendi uygulamanızı yazmak yerine yeniden kullanabileceğiniz çeşitli IRemoteTest uygulamaları içerir. Örneğin, InstrumentationTest, bir Android uygulamasının testlerini Android cihazda uzaktan çalıştırabilir, sonuçları ayrıştırabilir ve bu sonuçları ITestInvocationListener) iletebilir. Ayrıntılar için Test Türleri bölümüne bakın.

Mağaza testi sonuçları (I)

TF yapılandırması için varsayılan test dinleyicisi uygulaması, bir çağrının sonuçlarını stdout'a aktaran TextResultReporter'dır. Bunu açıklamak için önceki bölümdeki HelloWorldTest yapılandırmasını çalıştırın:

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

Bir çağrının sonuçlarını başka bir yerde (ör. bir dosyada) depolamak için yapılandırmanızda result_reporter etiketini kullanarak özel bir ITestInvocationListener uygulaması belirtin.

TF, test sonuçlarını ant JUnit XML yazıcısı tarafından kullanılana benzer bir biçimde bir XML dosyasına yazan XmlResultReporter dinleyicisini de içerir. Yapılandırmada result_reporter parametresini belirtmek için …/res/config/example/helloworld.xml config dosyasını düzenleyin:

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

Artık tradefed'i yeniden oluşturun ve hello world örneğini yeniden çalıştırın:

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

Bir XML dosyası oluşturulduğunu belirten günlük mesajına dikkat edin. Oluşturulan dosya şu şekilde görünür:

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

Kendi özel çağrı dinleyicilerinizi de yazabilirsiniz. Bunun için ITestInvocationListener arayüzünü uygulamanız yeterlidir.

Tradefed, birden fazla çağrı dinleyicisini destekler. Böylece test sonuçlarını birden fazla bağımsız hedefe gönderebilirsiniz. Bunun için yapılandırmanızda birden fazla <result_reporter> etiketi belirtmeniz yeterlidir.

Günlük kaydı tesisleri (D, I, R)

TF'nin günlük kaydı özellikleri şunları içerir:

  1. Cihazdan günlükleri yakalama (diğer adıyla cihaz logcat'i)
  2. Ana makinede çalışan Trade Federation çerçevesinden günlükleri kaydetme (diğer adıyla ana makine günlüğü)

TF çerçevesi, ayrılan cihazdan logcat'i otomatik olarak yakalar ve işlenmek üzere çağrı dinleyicisine gönderir. XmlResultReporter, yakalanan cihaz günlük kaydını dosya olarak kaydeder.

TF ana makine günlükleri, ddmlib Log sınıfı için CLog sarmalayıcısı kullanılarak raporlanır. HelloWorldTest'teki önceki System.out.println çağrısını CLog çağrısına dönüştürelim:

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

CLog, String.format'a benzer şekilde dize eklemeyi doğrudan işler. TF'yi yeniden oluşturup yeniden çalıştırdığınızda stdout'da aşağıdaki günlük mesajını görürsünüz:

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

tradefed varsayılan olarak ana makine günlük mesajlarını stdout'a gönderir. TF, mesajları bir dosyaya yazan bir günlük uygulaması da içerir: FileLogger. Dosya günlüğe kaydını eklemek için yapılandırmaya logger etiketi ekleyin ve FileLogger sınıfının tam adını belirtin:

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

Ardından, helloworld örneğini yeniden derleyip çalıştırın:

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
…

Günlük mesajı, ana makine günlüğünün yolunu belirtir. Bu yol görüntülendiğinde HelloWorldTest günlük mesajınızı içermelidir:

more /tmp/0/inv_6390011618174565918/host_log_4255420317120216614.txt

Örnek çıkış:

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

İşleme seçenekleri (D, I, R)

TF yapılandırmasından yüklenen nesneler (diğer adıyla yapılandırma nesneleri), @Option ek açıklamaları kullanılarak komut satırı bağımsız değişkenlerinden de veri alabilir.

Katılım için bir Yapılandırma nesnesi sınıfı, @Option ek açıklamasını bir üye alanına uygular ve alana benzersiz bir ad verir. Bu, üye alan değerinin bir komut satırı seçeneğiyle doldurulmasını sağlar (ayrıca bu seçeneği yapılandırma yardım sistemine otomatik olarak ekler).

Not: Tüm alan türleri desteklenmez. Desteklenen türlerin açıklaması için OptionSetter'a bakın.

HelloWorldTest'e bir @Option ekleyelim:

@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";

Ardından, HelloWorldTest işlevindeki seçeneğin değerini doğru şekilde aldığını göstermek için bir günlük mesajı ekleyelim:

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

Son olarak TF'yi yeniden oluşturun ve helloworld dosyasını çalıştırın. my_option varsayılan değerini içeren bir günlük mesajı göreceksiniz:

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

Komut satırından değer aktarma

my_option için bir değer iletin. my_option, bu değerle doldurulur:

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

TF yapılandırmaları, @Option alanları için otomatik olarak yardım metni gösteren bir yardım sistemi de içerir. Hemen deneyin. my_option ile ilgili yardım metnini görürsünüz:

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.

"Yalnızca önemli seçenekleri yazdırma" mesajını not edin. TF, seçenek yardım metinlerinin karmaşıklığını azaltmak için --help belirtildiğinde belirli bir @Option alan yardım metninin gösterilip gösterilmeyeceğini belirlemek üzere Option#importance özelliğini kullanır. --help-all, önem düzeyine bakılmaksızın tüm @Option alanları için her zaman yardım gösterir. Ayrıntılar için Option.Importance konusuna bakın.

Bir yapılandırmadan değer iletme

<option name="" value=""> öğesi ekleyerek yapılandırmada bir Option değeri de belirtebilirsiniz. helloworld.xml ile test edin:

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

helloworld dosyasını yeniden derleyip çalıştırdığınızda şu çıkışı elde edersiniz:

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

Yapılandırma yardımı da my_option için varsayılan değeri gösterecek şekilde güncellenir:

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

helloworld yapılandırmasına dahil edilen diğer yapılandırma nesneleri (ör. FileLogger) de seçenekleri kabul eder. --log-level-display seçeneği, stdout'da görünen günlükleri filtrelediği için ilgi çekicidir. Eğitimin başlarında "Merhaba, TF Dünyası! FileLogger kullanmaya başladıktan sonra "I have device …" günlük mesajı stdout'da gösterilmeyi durdurdu. --log-level-display bağımsız değişkenini ileterek stdout'a günlük kaydının ayrıntı düzeyini artırabilirsiniz.

Bunu şimdi deneyin. "Cihazım var" günlük mesajının bir dosyaya kaydedilmesinin yanı sıra stdout'da tekrar göründüğünü göreceksiniz:

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

Hepsi bu kadar.

Bir konuda takılırsanız Trade Federation kaynak kodunda dokümanda yer almayan birçok yararlı bilgi olduğunu hatırlatmak isteriz. Tüm yöntemler işe yaramazsa android-platform Google Grubu'nda "Trade Federation" ileti öznesini kullanarak soru sormayı deneyin.