Ví dụ kiểm tra TF từ đầu đến cuối

Hướng dẫn này hướng dẫn bạn cách tạo cấu hình thử nghiệm Liên đoàn Thương mại (Tradefed hoặc TF) "hello world" và cung cấp cho bạn phần giới thiệu thực tế về khung TF. Bắt đầu từ môi trường phát triển, bạn sẽ tạo một cấu hình đơn giản và thêm các tính năng.

Hướng dẫn này trình bày quy trình phát triển thử nghiệm dưới dạng một tập hợp các bài tập, mỗi bài tập bao gồm một số bước, minh họa cách xây dựng và tinh chỉnh dần dần cấu hình của bạn. Tất cả mã mẫu bạn cần để hoàn thành cấu hình thử nghiệm đều được cung cấp và tiêu đề của mỗi bài tập được chú thích bằng một chữ cái mô tả các vai trò liên quan đến bước đó:

  • D dành cho nhà phát triển
  • Tôi cho nhà tích hợp
  • R cho Người chạy thử

Sau khi hoàn thành phần hướng dẫn, bạn sẽ có cấu hình TF hoạt động và hiểu được nhiều khái niệm quan trọng trong khung TF.

Thành lập Liên đoàn Thương mại

Để biết chi tiết về cách thiết lập môi trường phát triển TF, hãy xem Machine Setup . Phần còn lại của hướng dẫn này giả định rằng bạn đã mở một shell đã được khởi tạo cho môi trường TF.

Để đơn giản, hướng dẫn này minh họa việc thêm một cấu hình và các lớp của nó vào thư viện lõi khung TF. Điều này có thể được mở rộng để phát triển các mô-đun bên ngoài cây nguồn bằng cách biên dịch JAR được giao dịch, sau đó biên dịch các mô-đun của bạn dựa trên JAR đó.

Tạo một lớp kiểm tra (D)

Hãy tạo một bài kiểm tra hello world chỉ gửi một thông báo tới thiết bị xuất chuẩn. Thử nghiệm giao dịch thường triển khai giao diện IRemoteTest . Đây là cách triển khai 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!");
    }
}

Lưu mã mẫu này vào <tree>/tools/tradefederation/core/src/com/android/tradefed/example/HelloWorldTest.java và xây dựng lại giao dịch từ shell của bạn:

m -jN

Lưu ý rằng CLog.i trong ví dụ trên được sử dụng để chuyển hướng đầu ra tới bảng điều khiển. Thông tin thêm về việc đăng nhập vào Liên đoàn Thương mại được mô tả trong Ghi nhật ký (D, I, R) .

Nếu quá trình xây dựng không thành công, hãy tham khảo Thiết lập máy để đảm bảo bạn không bỏ lỡ bước nào.

Tạo cấu hình (I)

Các thử nghiệm của Liên đoàn Thương mại được thực hiện bằng cách tạo Cấu hình , một tệp XML hướng dẫn giao dịch về loại thử nghiệm (hoặc các thử nghiệm) nào sẽ chạy, cũng như các mô-đun khác sẽ thực thi và theo thứ tự nào.

Hãy tạo Cấu hình mới cho HelloWorldTest của chúng tôi (lưu ý tên lớp đầy đủ của HelloWorldTest):

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

Lưu dữ liệu này vào tệp helloworld.xml ở bất kỳ đâu trên hệ thống tệp cục bộ của bạn (ví dụ: /tmp/helloworld.xml ). TF sẽ phân tích cú pháp tệp XML cấu hình (còn gọi là config ), tải lớp được chỉ định bằng cách sử dụng sự phản chiếu, khởi tạo nó, truyền nó tới IRemoteTest và gọi phương thức run của nó.

Chạy config (R)

Từ shell của bạn, khởi chạy bảng điều khiển đã giao dịch:

tradefed.sh

Đảm bảo thiết bị được kết nối với máy chủ và hiển thị với giao dịch:

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

Cấu hình có thể được thực thi bằng lệnh run <config> console. Thử:

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!

Bạn sẽ thấy "Xin chào, TF World!" đầu ra trên thiết bị đầu cuối.

Bạn có thể xác nhận rằng một lệnh đã được chạy xong bằng cách sử dụng list invocations hoặc li trong dấu nhắc bàn điều khiển và lệnh này sẽ không in gì cả. Nếu các lệnh hiện đang chạy, chúng sẽ hiển thị như sau:

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

Thêm cấu hình vào đường dẫn lớp (D, I, R)

Để thuận tiện cho việc triển khai, bạn cũng có thể gói các cấu hình vào chính các JAR được giao dịch. Tradefed tự động nhận dạng tất cả các cấu hình được đặt trong thư mục cấu hình trên đường dẫn lớp.

Để minh họa, hãy di chuyển tệp helloworld.xml vào thư viện lõi được giao dịch ( <tree>/tools/tradefederation/core/res/config/example/helloworld.xml ). Xây dựng lại bảng điều khiển đã giao dịch, khởi động lại bảng điều khiển đã giao dịch, sau đó yêu cầu giao dịch đã hiển thị danh sách các cấu hình từ đường dẫn lớp:

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

Bây giờ bạn có thể chạy cấu hình helloworld bằng cách sử dụng:

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!

Tương tác với thiết bị (D, R)

Cho đến nay, HelloWorldTest của chúng tôi không có gì thú vị. Chuyên môn của Tradefed là chạy thử nghiệm bằng thiết bị Android, vì vậy hãy thêm thiết bị Android vào thử nghiệm.

Các thử nghiệm có thể lấy tham chiếu đến thiết bị Android bằng cách sử dụng TestInformation , được khung cung cấp khi phương thức IRemoteTest#run được gọi.

Hãy sửa đổi thông báo in HelloWorldTest để hiển thị số sê-ri của thiết bị:

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

Bây giờ hãy xây dựng lại giao dịch và kiểm tra danh sách các thiết bị:

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

Hãy lưu ý số sê-ri được liệt kê là Có sẵn ; đó là thiết bị cần được phân bổ cho 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

Bạn sẽ thấy thông báo in mới hiển thị số sê-ri của thiết bị.

Gửi kết quả kiểm tra (D)

IRemoteTest báo cáo kết quả bằng cách gọi các phương thức trên phiên bản ITestInvocationListener được cung cấp cho phương thức #run . Bản thân khung TF chịu trách nhiệm báo cáo sự bắt đầu (thông qua ITestInvocationListener#invocationStarted ) và kết thúc (thông qua ITestInvocationListener#invocationEnded ) của mỗi Lời gọi.

Chạy thử nghiệm là một tập hợp các thử nghiệm hợp lý. Để báo cáo kết quả kiểm tra, IRemoteTest có trách nhiệm báo cáo thời điểm bắt đầu chạy thử, thời điểm bắt đầu và kết thúc của mỗi lần kiểm tra cũng như kết thúc quá trình chạy thử.

Đây là cách triển khai HelloWorldTest với một kết quả thử nghiệm không thành công.

@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 bao gồm một số triển khai IRemoteTest mà bạn có thể sử dụng lại thay vì tự viết từ đầu. Ví dụ: InstrumentationTest có thể chạy thử nghiệm ứng dụng Android từ xa trên thiết bị Android, phân tích kết quả và chuyển tiếp các kết quả đó tới ITestInvocationListener ). Để biết chi tiết, xem Các loại thử nghiệm .

Lưu trữ kết quả kiểm tra (I)

Việc triển khai trình nghe thử nghiệm mặc định cho cấu hình TF là TextResultReporter , kết quả của lệnh gọi tới thiết bị xuất chuẩn. Để minh họa, hãy chạy cấu hình HelloWorldTest từ phần trước:

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

Để lưu trữ kết quả của lệnh gọi ở nơi khác, chẳng hạn như trong tệp, hãy chỉ định triển khai ITestInvocationListener tùy chỉnh bằng cách sử dụng thẻ result_reporter trong cấu hình của bạn.

TF cũng bao gồm trình nghe XmlResultReporter , trình nghe này ghi kết quả kiểm tra vào một tệp XML theo định dạng tương tự như định dạng được sử dụng bởi trình soạn thảo XML ant JUnit. Để chỉ định result_reporter trong cấu hình, hãy chỉnh sửa cấu hình …/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>

Bây giờ hãy xây dựng lại giao dịch và chạy lại mẫu 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

Lưu ý thông báo nhật ký cho biết tệp XML đã được tạo; tệp được tạo sẽ trông như thế này:

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

Bạn cũng có thể viết trình nghe lệnh gọi tùy chỉnh của riêng mình—chúng chỉ cần triển khai giao diện ITestInvocationListener .

Tradefed hỗ trợ nhiều trình xử lý lệnh gọi, vì vậy bạn có thể gửi kết quả kiểm tra đến nhiều đích độc lập. Để thực hiện việc này, chỉ cần chỉ định nhiều thẻ <result_reporter> trong config.

Cơ sở ghi nhật ký (D, I, R)

Cơ sở khai thác gỗ của TF bao gồm khả năng:

  1. Ghi nhật ký từ thiết bị (còn gọi là logcat thiết bị)
  2. Ghi lại nhật ký từ khung Liên đoàn Thương mại đang chạy trên máy chủ (hay còn gọi là nhật ký máy chủ)

Khung TF tự động ghi lại logcat từ thiết bị được phân bổ và gửi nó đến trình nghe lệnh gọi để xử lý. Sau đó XmlResultReporter sẽ lưu logcat thiết bị đã chụp dưới dạng tệp.

Nhật ký máy chủ TF được báo cáo bằng trình bao bọc CLog cho lớp Nhật ký ddmlib. Hãy chuyển đổi lệnh gọi System.out.println trước đó trong HelloWorldTest thành lệnh gọi CLog :

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

CLog xử lý trực tiếp nội suy chuỗi, tương tự như String.format . Khi bạn xây dựng lại và chạy lại TF, bạn sẽ thấy thông báo tường trình trên thiết bị xuất chuẩn:

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

Theo mặc định, giao dịch xuất thông điệp nhật ký máy chủ thành stdout . TF cũng bao gồm việc triển khai nhật ký để ghi thông báo vào một tệp: FileLogger . Để thêm tính năng ghi nhật ký tệp, hãy thêm thẻ logger vào cấu hình, chỉ định tên lớp đầy đủ của 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>

Bây giờ, hãy xây dựng lại và chạy lại ví dụ 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
…

Thông báo nhật ký cho biết đường dẫn của nhật ký máy chủ, khi xem sẽ chứa thông báo nhật ký HelloWorldTest của bạn:

more /tmp/0/inv_6390011618174565918/host_log_4255420317120216614.txt

Đầu ra ví dụ:

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

Tùy chọn xử lý (D, I, R)

Các đối tượng được tải từ Cấu hình TF (còn gọi là đối tượng Cấu hình ) cũng có thể nhận dữ liệu từ các đối số dòng lệnh thông qua việc sử dụng chú thích @Option .

Để tham gia, lớp đối tượng Cấu hình sẽ áp dụng chú thích @Option cho trường thành viên và cung cấp cho nó một tên duy nhất. Điều này cho phép giá trị trường thành viên đó được điền thông qua tùy chọn dòng lệnh (và cũng tự động thêm tùy chọn đó vào hệ thống trợ giúp cấu hình).

Lưu ý: Không phải tất cả các loại trường đều được hỗ trợ. Để biết mô tả về các loại được hỗ trợ, hãy xem OptionSetter .

Hãy thêm @Option vào 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";

Tiếp theo, hãy thêm thông điệp tường trình để hiển thị giá trị của tùy chọn trong HelloWorldTest để chúng tôi có thể chứng minh rằng nó đã được nhận chính xác:

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

Cuối cùng, xây dựng lại TF và chạy helloworld; bạn sẽ thấy thông báo tường trình có giá trị mặc định my_option :

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

Truyền giá trị từ dòng lệnh

Chuyển một giá trị cho my_option ; bạn sẽ thấy my_option được điền với giá trị đó:

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

Cấu hình TF cũng bao gồm hệ thống trợ giúp, hệ thống này tự động hiển thị văn bản trợ giúp cho các trường @Option . Hãy thử ngay bây giờ và bạn sẽ thấy văn bản trợ giúp cho 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.

Lưu ý thông báo về việc "chỉ in các tùy chọn quan trọng". Để giảm sự lộn xộn của trợ giúp tùy chọn, TF sử dụng thuộc tính Option#importance để xác định xem có hiển thị văn bản trợ giúp trường @Option cụ thể khi --help được chỉ định hay không. --help-all luôn hiển thị trợ giúp cho tất cả các trường @Option , bất kể tầm quan trọng. Để biết chi tiết, xem Option.Importance .

Truyền giá trị từ một cấu hình

Bạn cũng có thể chỉ định giá trị Tùy chọn trong cấu hình bằng cách thêm phần tử <option name="" value=""> . Kiểm tra nó bằng helloworld.xml :

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

Việc xây dựng lại và chạy helloworld bây giờ sẽ tạo ra kết quả như sau:

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

Trợ giúp cấu hình cũng sẽ cập nhật để cho biết giá trị mặc định của my_option :

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

Các đối tượng cấu hình khác có trong cấu hình helloworld, chẳng hạn như FileLogger , cũng chấp nhận các tùy chọn. Tùy chọn --log-level-display rất thú vị vì nó lọc các nhật ký hiển thị trên thiết bị xuất chuẩn. Trước đó trong hướng dẫn, bạn có thể nhận thấy thông báo nhật ký "Xin chào, TF World! Tôi có thiết bị …' đã ngừng hiển thị trên thiết bị xuất chuẩn sau khi chúng tôi chuyển sang sử dụng FileLogger . Bạn có thể tăng mức độ chi tiết của việc ghi nhật ký vào thiết bị xuất chuẩn bằng cách chuyển vào --log-level-display arg.

Hãy thử điều này ngay bây giờ và bạn sẽ thấy thông báo nhật ký 'Tôi có thiết bị' xuất hiện lại trên thiết bị xuất chuẩn, ngoài việc được ghi vào một tệp:

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

Chỉ vậy thôi các bạn!

Xin nhắc lại, nếu bạn đang mắc kẹt ở điều gì đó, mã nguồn của Liên đoàn Thương mại có rất nhiều thông tin hữu ích không được đưa ra trong tài liệu. Nếu vẫn thất bại, hãy thử hỏi trên Nhóm Google nền tảng Android , với "Liên đoàn Thương mại" trong chủ đề thư.