نمونه تست پایان به پایان TF

این آموزش شما را از طریق ایجاد پیکربندی آزمایشی فدراسیون تجارت "سلام جهان" (Tradefed یا TF) راهنمایی می کند و به شما یک معرفی عملی با چارچوب TF می دهد. با شروع از یک محیط توسعه، یک پیکربندی ساده ایجاد کرده و ویژگی هایی را اضافه خواهید کرد.

این آموزش، فرآیند توسعه آزمون را به عنوان مجموعه‌ای از تمرین‌ها، که هر کدام از چندین مرحله تشکیل شده است، ارائه می‌کند که نشان می‌دهد چگونه پیکربندی خود را بسازید و به تدریج اصلاح کنید. تمام کد نمونه ای که برای تکمیل پیکربندی تست نیاز دارید ارائه شده است و عنوان هر تمرین با یک حرف توضیح داده شده است که نقش های دخیل در آن مرحله را توضیح می دهد:

  • D برای توسعه دهنده
  • من برای انتگرال
  • R برای تست دونده

پس از تکمیل آموزش، پیکربندی TF کارآمدی خواهید داشت و بسیاری از مفاهیم مهم در چارچوب TF را درک خواهید کرد.

تشکیل فدراسیون تجارت

برای جزئیات در مورد تنظیم محیط توسعه TF، به تنظیمات ماشین مراجعه کنید. بقیه این آموزش فرض می کند که شما یک پوسته باز دارید که در محیط TF مقداردهی اولیه شده است.

برای سادگی، این آموزش اضافه کردن یک پیکربندی و کلاس‌های آن به کتابخانه هسته چارچوب TF را نشان می‌دهد. این را می توان به توسعه ماژول ها در خارج از درخت منبع با کامپایل JAR تجارت شده و سپس کامپایل کردن ماژول های خود در برابر آن JAR گسترش داد.

ایجاد یک کلاس آزمایشی (D)

بیایید یک آزمایش hello world ایجاد کنیم که فقط یک پیام به stdout ارسال می کند. یک تست tradefed معمولا رابط IRemoteTest را پیاده سازی می کند. در اینجا یک پیاده سازی برای 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!");
    }
}

این کد نمونه را در <tree>/tools/tradefederation/core/src/com/android/tradefed/example/HelloWorldTest.java ذخیره کنید و tradefed را از پوسته خود بازسازی کنید:

m -jN

توجه داشته باشید که CLog.i در مثال بالا برای هدایت خروجی به کنسول استفاده می شود. اطلاعات بیشتر در مورد ورود به سیستم در فدراسیون تجارت در Logging (D, I, R) توضیح داده شده است.

اگر ساخت موفق نشد، با Machine Setup مشورت کنید تا مطمئن شوید که یک مرحله را از دست نداده اید.

ایجاد یک پیکربندی (I)

تست‌های Trade Federation با ایجاد یک Configuration ، یک فایل XML که به tradefed دستور می‌دهد که کدام تست (یا تست‌ها) را اجرا کنند، و همچنین ماژول‌های دیگر را به چه ترتیبی اجرا کنند، قابل اجرا می‌شوند.

اجازه دهید یک پیکربندی جدید برای HelloWorldTest خود ایجاد کنیم (به نام کامل کلاس HelloWorldTest توجه کنید):

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

این داده ها را در یک فایل helloworld.xml در هر جایی از سیستم فایل محلی خود ذخیره کنید (به عنوان مثال /tmp/helloworld.xml ). TF فایل Configuration XML (معروف به config ) را تجزیه می کند، کلاس مشخص شده را با استفاده از انعکاس بارگذاری می کند، آن را نمونه سازی می کند، آن را به IRemoteTest می فرستد و متد run آن را فراخوانی می کند.

پیکربندی (R) را اجرا کنید

از پوسته خود، کنسول tradefed را راه اندازی کنید:

tradefed.sh

اطمینان حاصل کنید که یک دستگاه به دستگاه میزبان متصل است و برای Tradefed قابل مشاهده است:

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

تنظیمات را می توان با استفاده از دستور run <config> کنسول اجرا کرد. امتحان کنید:

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!

شما باید "Hello, TF World!" خروجی روی ترمینال

می‌توانید تأیید کنید که یک فرمان با استفاده از list invocations یا li در فرمان کنسول اجرا می‌شود و نباید چیزی چاپ شود. اگر دستورات در حال اجرا هستند، به صورت زیر نمایش داده می شوند:

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

پیکربندی را به مسیر کلاس اضافه کنید (D, I, R)

برای سهولت در استقرار، می‌توانید پیکربندی‌ها را نیز در خود JAR‌های عرضه‌شده باندل کنید. Tradefed به طور خودکار تمام تنظیمات موجود در پوشه های پیکربندی در مسیر کلاس را تشخیص می دهد.

برای نشان دادن، فایل helloworld.xml را به کتابخانه اصلی tradefed منتقل کنید ( <tree>/tools/tradefederation/core/res/config/example/helloworld.xml ). Tradefed را بازسازی کنید، کنسول tradefed را مجددا راه اندازی کنید، سپس از tradefed بخواهید لیست تنظیمات را از classpath نمایش دهد:

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

اکنون می توانید پیکربندی helloworld را با استفاده از:

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!

تعامل با یک دستگاه (D, R)

تاکنون، HelloWorldTest ما کار جالبی انجام نداده است. تخصص Tradefed اجرای آزمایش‌ها با استفاده از دستگاه‌های Android است، بنابراین اجازه دهید یک دستگاه Android را به آزمایش اضافه کنیم.

تست‌ها می‌توانند با استفاده از TestInformation ، که توسط فریمورک ارائه می‌شود، هنگام فراخوانی متد IRemoteTest#run ارجاع به دستگاه Android دریافت کنند.

بیایید پیام چاپی HelloWorldTest را برای نمایش شماره سریال دستگاه تغییر دهیم:

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

اکنون tradefed را بازسازی کنید و لیست دستگاه ها را بررسی کنید:

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

به شماره سریال ذکر شده به عنوان موجود توجه کنید. این دستگاهی است که باید به 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

شما باید پیام چاپ جدید را مشاهده کنید که شماره سریال دستگاه را نشان می دهد.

ارسال نتایج آزمون (D)

IRemoteTest نتایج را با فراخوانی متدهایی در نمونه ITestInvocationListener ارائه شده به روش #run گزارش می‌کند. چارچوب TF خود مسئول گزارش شروع (از طریق ITestInvocationListener#invocationStarted ) و پایان (از طریق ITestInvocationListener#invocationEnded ) هر Invocation است.

اجرای آزمایشی مجموعه ای منطقی از تست ها است. برای گزارش نتایج آزمون، IRemoteTest مسئول گزارش شروع اجرای آزمایشی، شروع و پایان هر آزمون و پایان اجرای آزمایشی است.

در اینجا نحوه اجرای HelloWorldTest ممکن است با یک نتیجه آزمایش ناموفق به نظر برسد.

@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 شامل چندین پیاده سازی IRemoteTest است که می توانید به جای نوشتن از ابتدا از آنها استفاده مجدد کنید. برای مثال، InstrumentationTest می‌تواند آزمایش‌های یک برنامه Android را از راه دور بر روی یک دستگاه Android اجرا کند، نتایج را تجزیه کند و آن نتایج را به ITestInvocationListener ارسال کند. برای جزئیات، به انواع تست مراجعه کنید.

ذخیره نتایج آزمون (I)

اجرای آزمایشی شنونده پیش فرض برای پیکربندی TF TextResultReporter است که نتایج فراخوانی را به stdout می‌ریزد. برای نشان دادن، پیکربندی HelloWorldTest را از قسمت قبل اجرا کنید:

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

برای ذخیره نتایج یک فراخوانی در جای دیگری، مانند یک فایل، یک پیاده سازی سفارشی ITestInvocationListener را با استفاده از تگ result_reporter در پیکربندی خود مشخص کنید.

TF همچنین شامل شنونده XmlResultReporter است که نتایج آزمایش را در یک فایل XML در قالبی شبیه به فرمت مورد استفاده توسط نویسنده ant JUnit XML می نویسد. برای مشخص کردن result_reporter در پیکربندی، پیکربندی …/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>

اکنون tradefed را بازسازی کنید و نمونه 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

به پیام ورود به سیستم توجه کنید مبنی بر اینکه یک فایل XML ایجاد شده است. فایل تولید شده باید به شکل زیر باشد:

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

همچنین می‌توانید شنونده‌های فراخوان سفارشی خود را بنویسید—آنها به سادگی باید رابط ITestInvocationListener را پیاده‌سازی کنند.

Tradefed از چندین شنونده فراخوانی پشتیبانی می کند، بنابراین می توانید نتایج آزمایش را به چندین مقصد مستقل ارسال کنید. برای انجام این کار، کافی است چندین تگ <result_reporter> را در پیکربندی خود مشخص کنید.

امکانات جنگلداری (D, I, R)

امکانات ورود به سیستم TF شامل توانایی زیر است:

  1. ثبت گزارش‌ها از دستگاه (معروف به دستگاه logcat)
  2. ثبت گزارش‌ها از چارچوب فدراسیون تجارت در حال اجرا بر روی دستگاه میزبان (معروف به گزارش میزبان)

چارچوب TF به طور خودکار logcat را از دستگاه اختصاص داده شده می گیرد و آن را برای پردازش به شنونده فراخوان می فرستد. سپس XmlResultReporter logcat دستگاه ضبط شده را به عنوان یک فایل ذخیره می کند.

گزارش‌های میزبان TF با استفاده از بسته‌بندی CLog برای کلاس ddmlib Log گزارش می‌شوند. بیایید تماس قبلی System.out.println در HelloWorldTest را به یک تماس CLog تبدیل کنیم:

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

CLog به طور مستقیم از درون یابی رشته ها استفاده می کند، مشابه String.format . هنگامی که TF را بازسازی و دوباره اجرا می کنید، باید پیام log را در stdout ببینید:

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

به طور پیش‌فرض، tradefed پیام‌های گزارش میزبان را به stdout خروجی می‌دهد . TF همچنین شامل یک پیاده سازی گزارش است که پیام ها را در یک فایل می نویسد: FileLogger . برای افزودن گزارش فایل، یک تگ logger به پیکربندی اضافه کنید و نام کلاس کامل 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>

اکنون، نمونه 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
…

پیام log مسیر گزارش میزبان را نشان می دهد، که در صورت مشاهده، باید حاوی پیام ورود به سیستم HelloWorldTest شما باشد:

more /tmp/0/inv_6390011618174565918/host_log_4255420317120216614.txt

خروجی نمونه:

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

گزینه های مدیریت (D، I، R)

اشیاء بارگیری شده از یک پیکربندی TF (معروف به اشیاء پیکربندی ) همچنین می توانند داده ها را از آرگومان های خط فرمان از طریق استفاده از حاشیه نویسی @Option دریافت کنند.

برای شرکت، یک کلاس شی Configuration حاشیه نویسی @Option را در فیلد عضو اعمال می کند و یک نام منحصر به فرد برای آن ایجاد می کند. این مقدار فیلد عضو را قادر می سازد از طریق گزینه خط فرمان پر شود (و همچنین به طور خودکار آن گزینه را به سیستم راهنمای پیکربندی اضافه می کند).

توجه: همه انواع فیلدها پشتیبانی نمی شوند. برای توضیح انواع پشتیبانی شده، به OptionSetter مراجعه کنید.

بیایید یک @Option به 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";

در مرحله بعد، بیایید یک پیام گزارش برای نمایش مقدار گزینه در HelloWorldTest اضافه کنیم تا بتوانیم نشان دهیم که به درستی دریافت شده است:

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

در نهایت، TF را بازسازی کنید و helloworld را اجرا کنید. شما باید یک پیام گزارش با مقدار پیش فرض my_option را ببینید:

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

مقادیر را از خط فرمان منتقل کنید

یک مقدار برای my_option ارسال کنید. شما باید my_option را با این مقدار مشاهده کنید:

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

تنظیمات TF همچنین شامل یک سیستم راهنما است که به طور خودکار متن راهنما را برای فیلدهای @Option نمایش می دهد. اکنون آن را امتحان کنید، و باید متن راهنمای 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.

به پیام «چاپ فقط گزینه‌های مهم» توجه کنید. برای کاهش شلوغی کمک گزینه، TF از ویژگی Option#importance استفاده می‌کند تا تعیین کند که آیا یک متن راهنمای فیلد @Option خاص در زمانی که --help مشخص شده است نشان داده شود یا خیر. --help-all همیشه برای همه فیلدهای @Option بدون در نظر گرفتن اهمیت، کمک را نشان می دهد. برای جزئیات، به Option.Importance مراجعه کنید.

مقادیر را از یک پیکربندی منتقل کنید

همچنین می توانید با افزودن عنصر <option name="" value=""> یک مقدار Option را در پیکربندی مشخص کنید. آن را با استفاده از helloworld.xml تست کنید:

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

بازسازی و اجرای helloworld اکنون باید این خروجی را تولید کند:

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

راهنمای پیکربندی نیز باید به‌روزرسانی شود تا مقدار پیش‌فرض my_option را نشان دهد:

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

سایر اشیاء پیکربندی موجود در پیکربندی helloworld، مانند FileLogger نیز گزینه‌ها را می‌پذیرند. گزینه --log-level-display جالب است زیرا لاگ هایی را که در stdout نشان داده می شوند را فیلتر می کند. قبلاً در آموزش، ممکن است متوجه شده باشید که پیام گزارش "Hello, TF World! I have device…" پس از اینکه ما به استفاده از FileLogger تغییر دادیم --log-level-display در stdout نمایش داده نمی شود. --log-level-display arg.

اکنون این را امتحان کنید، و باید مشاهده کنید که پیام گزارش "I have device" در stdout دوباره ظاهر می شود، علاوه بر اینکه به یک فایل وارد می شود:

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

این همه، مردم!

به عنوان یادآوری، اگر در مورد چیزی گیر کرده اید، کد منبع فدراسیون تجارت اطلاعات مفید زیادی دارد که در اسناد نمایش داده نشده است. اگر همه چیز شکست خورد، سعی کنید از Google Group پلتفرم اندروید بپرسید، با عبارت Trade Federation در موضوع پیام.