Hướng dẫn này sẽ hướng dẫn bạn tạo cấu hình kiểm thử "xin chào thế giới" cho Liên minh thương mại (Tradefed hoặc TF) và giới thiệu thực tế về khung TF. Bắt đầu từ mộ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 kiểm thử dưới dạng một bộ bài tập, mỗi bài tập bao gồm một số bước minh hoạ cách tạo và dần dần tinh chỉnh cấu hình. Tất cả mã mẫu bạn cần để hoàn tất cấu hình kiểm thử đề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 trong bước đó:
- D cho Nhà phát triển
- I cho Trình tích hợp
- R cho Trình chạy kiểm thử
Sau khi hoàn tất hướng dẫn này, bạn sẽ có một cấu hình TF hoạt động và hiểu được nhiều khái niệm quan trọng trong khung TF.
Thiết lập Liên minh thương mại
Để biết thông tin chi tiết về cách thiết lập môi trường phát triển TF, hãy xem phần Thiết lập máy. 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 chạy cho môi trường TF.
Để đơn giản, hướng dẫn này minh hoạ cách thêm một cấu hình và các lớp của cấu hình đó vào thư viện cốt lõi của khung TF. Bạn có thể mở rộng tính năng này để phát triển các mô-đun bên ngoài cây nguồn bằng cách biên dịch tệp JAR được phân phối thương mại, sau đó biên dịch các mô-đun của bạn dựa trên tệp JAR đó.
Tạo lớp kiểm thử (D)
Hãy tạo một chương trình kiểm thử hello world chỉ kết xuất một thông báo vào stdout. Quy trình kiểm thử được cung cấp thường triển khai giao diện IRemoteTest. Dưới đâ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à tạo lại tradefed từ shell:
m -jN
Xin lưu ý rằng CLog.i
trong ví dụ trên được dùng để chuyển hướng đầu ra đến bảng điều khiển. Thông tin khác về cách đăng nhập vào Trade Federation được mô tả trong phần Ghi nhật ký (D, I, R).
Nếu bản dựng không thành công, hãy tham khảo phần 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)
Bạn có thể thực thi các kiểm thử của Trade Federation bằng cách tạo một Cấu hình (Configuration). Đây là một tệp XML hướng dẫn Tradefed về kiểm thử (hoặc các kiểm thử) cần chạy, cũng như các mô-đun khác cần thực thi và thứ tự thực thi.
Hãy tạo một Cấu hình mới cho HelloWorldTest (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ộ (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 đã chỉ định bằng cách phản chiếu, tạo bản sao lớp đó, truyền lớp đó vào IRemoteTest
và gọi phương thức run
của lớp đó.
Chạy cấu hình (R)
Trên shell, hãy khởi chạy bảng điều khiển tradefed:
tradefed.sh
Đảm bảo thiết bị được kết nối với máy chủ lưu trữ và hiển thị với tradefed:
tf> list devices Serial State Product Variant Build Battery 004ad9880810a548 Available mako mako JDQ39 100
Bạn có thể thực thi cấu hình bằng lệnh bảng điều khiển run <config>
. Hãy 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 kết quả "Hello, TF World!" (Xin chào, TF World!) trên thiết bị đầu cuối.
Bạn có thể xác nhận rằng một lệnh đã chạy xong bằng cách sử dụng list invocations
hoặc l i
trong lời nhắc của bảng điều khiển và lệnh này sẽ không in ra gì cả. Nếu các lệnh đang chạy, thì các lệnh đó 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 tệp JAR của tradefed. Tradefed tự động nhận dạng tất cả cấu hình được đặt trong thư mục config trên đường dẫn lớp.
Để minh hoạ, hãy di chuyển tệp helloworld.xml
vào thư viện cốt lõi của tradefed (<tree>/tools/tradefederation/core/res/config/example/helloworld.xml
). Tạo lại tradefed, khởi động lại bảng điều khiển tradefed, sau đó yêu cầu tradefed hiển thị danh sách cấu hình từ đường dẫn lớp:
tf> list configs […] example/helloworld: Runs the hello world test
Giờ đây, 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 ta chưa làm được gì thú vị. Chuyên môn của Tradefed là chạy kiểm thử bằng các thiết bị Android, vì vậy, hãy thêm một thiết bị Android vào kiểm thử.
Các chương trình kiểm thử có thể tham chiếu đến một thiết bị Android bằng cách sử dụng TestInformation
do 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 tạo lại tradefed và kiểm tra danh sách thiết bị:
tradefed.sh
tf> list devices Serial State Product Variant Build Battery 004ad9880810a548 Available mako mako JDQ39 100
Hãy ghi lại 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 thử (D)
IRemoteTest
báo cáo kết quả bằng cách gọi các phương thức trên thực thể 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 thời điểm bắt đầu (thông qua ITestInvocationListener#invocationStarted) và kết thúc (thông qua ITestInvocationListener#invocationEnded) của mỗi Lệnh gọi.
Chạy kiểm thử là một tập hợp các kiểm thử hợp lý. Để báo cáo kết quả kiểm thử, IRemoteTest
chịu trách nhiệm báo cáo thời điểm bắt đầu chạy kiểm thử, thời điểm bắt đầu và kết thúc mỗi lần kiểm thử cũng như thời điểm kết thúc chạy kiểm thử.
Sau đây là cách triển khai HelloWorldTest với một kết quả kiểm thử 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ố cách triển khai IRemoteTest
mà bạn có thể sử dụng lại thay vì viết từ đầu. Ví dụ: InstrumentationTest có thể chạy các chương trình kiểm thử của ứng dụng Android từ xa trên một thiết bị Android, phân tích cú pháp kết quả và chuyển tiếp các kết quả đó đến ITestInvocationListener
). Để biết thông tin chi tiết, hãy xem Các loại kiểm thử.
Lưu trữ kết quả kiểm thử (I)
Phương thức triển khai trình nghe kiểm thử mặc định cho cấu hình TF là TextResultReporter. Phương thức này sẽ kết xuất kết quả của lệnh gọi vào stdout. Để minh hoạ, 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 cách triển khai ITestInvocationListener
tuỳ chỉnh bằng cách sử dụng thẻ result_reporter
trong cấu hình.
TF cũng bao gồm trình nghe XmlResultReporter. Trình nghe này sẽ ghi kết quả kiểm thử vào tệp XML theo định dạng tương tự như định dạng mà trình ghi XML JUnit ant sử dụng. Để 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 tạo lại tradefed 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 đã tạo sẽ có dạng như sau:
<?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ể tự viết trình nghe lệnh gọi tuỳ chỉnh – các trình nghe này chỉ cần triển khai giao diện ITestInvocationListener.
Tradefed hỗ trợ nhiều trình nghe lệnh gọi, vì vậy, bạn có thể gửi kết quả kiểm thử đến nhiều đích đến độc lập. Để làm việc này, bạn chỉ cần chỉ định nhiều thẻ <result_reporter>
trong cấu hình.
Cơ sở ghi nhật ký (D, I, R)
Các cơ sở ghi nhật ký của TF bao gồm khả năng:
- Ghi nhật ký từ thiết bị (còn gọi là logcat thiết bị)
- Ghi nhật ký từ khung Trade Federation chạy trên máy chủ lưu trữ (còn gọi là nhật ký máy chủ lưu trữ)
Khung TF tự động chụp logcat từ thiết bị được phân bổ và gửi logcat đó đế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ủ lưu trữ TF được báo cáo bằng cách sử dụ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 hoạt động nội suy chuỗi, tương tự như String.format
. Khi tạo lại và chạy lại TF, bạn sẽ thấy thông báo nhật ký trên stdout:
tf> run example/helloworld … 05-16 21:30:46 I/HelloWorldTest: Hello, TF World! I have device 004ad9880810a548 …
Theo mặc định, tradefed xuất thông điệp nhật ký máy chủ sang stdout. TF cũng bao gồm một phương thứ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 tạo 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, thông báo này phải chứa thông báo nhật ký HelloWorldTest:
more /tmp/0/inv_6390011618174565918/host_log_4255420317120216614.txt
Kết quả điểm dữ liệu:
… 05-16 21:38:21 I/HelloWorldTest: Hello, TF World! I have device 004ad9880810a548
Xử lý các tuỳ chọn (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ú giải @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 tên riêng biệt cho trường đó. Thao tác này cho phép điền giá trị trường thành viên đó thông qua tuỳ chọn dòng lệnh (và cũng tự động thêm tuỳ chọn đó vào hệ thống trợ giúp cấu hình).
Lưu ý: Không phải loại trường nào cũng được hỗ trợ. Để biết nội dung 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 một thông điệp nhật ký để hiển thị giá trị của tuỳ chọn trong HelloWorldTest để chúng ta có thể chứng minh rằng thông điệp đã đượ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, hãy tạo lại TF và chạy helloworld; bạn sẽ thấy thông điệp nhật ký 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
Truyền vào một giá trị cho my_option
; bạn sẽ thấy my_option
được điền sẵn 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 một hệ thống trợ giúp, tự động hiển thị văn bản trợ giúp cho các trường @Option
. Hãy thử ngay 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 tuỳ chọn quan trọng". Để giảm bớt sự lộn xộn của văn bản trợ giúp về tuỳ 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 về trường @Option
cụ thể hay không khi chỉ định --help
. --help-all
luôn hiển thị thông tin trợ giúp cho tất cả các trường @Option
, bất kể mức độ quan trọng. Để biết thông tin chi tiết, hãy xem Option.Importance.
Truyền giá trị từ một cấu hình
Bạn cũng có thể chỉ định giá trị Tuỳ chọn trong cấu hình bằng cách thêm phần tử <option name="" value="">
. Kiểm thử bằng helloworld.xml
:
<test class="com.android.tradefed.example.HelloWorldTest" > <option name="my_option" value="fromxml" /> </test>
Giờ đây, việc tạo lại và chạy helloworld sẽ tạo ra kết quả sau:
05-24 20:38:25 I/HelloWorldTest: I received option 'fromxml'
Phần trợ giúp về 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 tuỳ chọn. Tuỳ chọn --log-level-display
rất thú vị vì nó lọc các nhật ký xuất hiện trên stdout. Ở phần đầu của hướng dẫn này, bạn có thể đã nhận thấy thông báo "Hello, TF World! Thông báo nhật ký "I have device …" (Tôi có thiết bị …) đã ngừng hiển thị trên stdout sau khi chúng ta 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 stdout bằng cách truyền vào đối số --log-level-display
.
Hãy thử ngay và bạn sẽ thấy thông báo nhật ký "I have device" (Tôi có thiết bị) xuất hiện trở lại trên stdout, ngoài việc được ghi nhật ký 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
Vậy là xong!
Xin lưu ý rằng nếu bạn gặp khó khăn, mã nguồn của Liên minh thương mại có nhiều thông tin hữu ích không được trình bày trong tài liệu. Nếu không có cách nào khác, hãy thử hỏi trên Nhóm Google android-platform, với tiêu đề thư là "Trade Federation" (Liên minh thương mại).