บทช่วยสอนนี้จะแนะนำคุณตลอดการสร้างการกำหนดค่าการทดสอบของสหพันธ์การค้า (Tradefed หรือ TF) "สวัสดีชาวโลก" และให้คำแนะนำเบื้องต้นเกี่ยวกับกรอบงาน TF แบบลงมือปฏิบัติจริง เริ่มต้นจากสภาพแวดล้อมการพัฒนา คุณจะสร้างการกำหนดค่าที่เรียบง่ายและเพิ่มคุณสมบัติต่างๆ
บทช่วยสอนนี้นำเสนอกระบวนการพัฒนาการทดสอบเป็นชุดแบบฝึกหัด แต่ละบทประกอบด้วยหลายขั้นตอน ซึ่งสาธิตวิธีการสร้างและค่อยๆ ปรับแต่งการกำหนดค่าของคุณ มีโค้ดตัวอย่างทั้งหมดที่คุณต้องใช้ในการกำหนดค่าการทดสอบให้ครบถ้วน และชื่อของแบบฝึกหัดแต่ละรายการจะมีคำอธิบายประกอบด้วยตัวอักษรที่อธิบายบทบาทที่เกี่ยวข้องในขั้นตอนนั้น:
- D สำหรับนักพัฒนา
- ฉัน สำหรับ Integrator
- R สำหรับนักวิ่งทดสอบ
หลังจากเสร็จสิ้นบทช่วยสอน คุณจะมีการกำหนดค่า TF ที่ใช้งานได้ และเข้าใจแนวคิดที่สำคัญมากมายในกรอบงาน TF
จัดตั้งสหพันธ์การค้า
สำหรับรายละเอียดเกี่ยวกับการตั้งค่าสภาพแวดล้อมการพัฒนา TF โปรดดู การตั้งค่าเครื่อง ส่วนที่เหลือของบทช่วยสอนนี้จะถือว่าคุณมีเชลล์ที่เปิดอยู่ซึ่งได้รับการเตรียมใช้งานกับสภาพแวดล้อม TF
เพื่อความง่าย บทช่วยสอนนี้จะแสดงการเพิ่มการกำหนดค่าและคลาสลงในไลบรารีหลักของเฟรมเวิร์ก TF สิ่งนี้สามารถขยายไปสู่การพัฒนาโมดูลภายนอกแผนผังต้นทางโดยการคอมไพล์ JAR ที่แลกเปลี่ยนแล้ว จากนั้นคอมไพล์โมดูลของคุณกับ JAR นั้น
สร้างคลาสทดสอบ (D)
มาสร้างการทดสอบสวัสดีโลกที่เพิ่งทิ้งข้อความไปที่ 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
ในตัวอย่างด้านบนใช้เพื่อกำหนดเอาต์พุตไปยังคอนโซลโดยตรง ข้อมูลเพิ่มเติมเกี่ยวกับการเข้าสู่ระบบในสหพันธ์การค้ามีอธิบายไว้ใน การบันทึก (D, I, R)
หากการสร้างไม่สำเร็จ ให้ปรึกษา การตั้งค่าเครื่อง เพื่อให้แน่ใจว่าคุณไม่พลาดขั้นตอนใดขั้นตอนหนึ่ง
สร้างการกำหนดค่า (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 จะแยกวิเคราะห์ไฟล์ XML การกำหนดค่า (aka config ) โหลดคลาสที่ระบุโดยใช้การสะท้อน สร้างอินสแตนซ์ ส่งไปที่ IRemoteTest
และเรียกใช้วิธี run
เรียกใช้การกำหนดค่า (R)
จากเชลล์ของคุณ เปิดคอนโซลที่แลกเปลี่ยนแล้ว:
tradefed.sh
ตรวจสอบให้แน่ใจว่าอุปกรณ์เชื่อมต่อกับเครื่องโฮสต์และสามารถมองเห็นการแลกเปลี่ยนได้:
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}'
เพิ่มการกำหนดค่าให้กับ classpath (D, I, R)
เพื่อความสะดวกในการปรับใช้ คุณยังสามารถรวมการกำหนดค่าเข้ากับ JAR ที่แลกเปลี่ยนด้วยตนเองได้ Tradefed จะจดจำการกำหนดค่าทั้งหมดที่อยู่ในโฟลเดอร์ กำหนดค่า บน classpath โดยอัตโนมัติ
เพื่อแสดงให้เห็น ให้ย้ายไฟล์ 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 ลงในการทดสอบกันดีกว่า
การทดสอบสามารถรับการอ้างอิงไปยังอุปกรณ์ Android ได้โดยใช้ TestInformation
ซึ่งจัดทำโดยเฟรมเวิร์กเมื่อมีการเรียกใช้เมธอด IRemoteTest#run
มาแก้ไขข้อความพิมพ์ HelloWorldTest เพื่อแสดงหมายเลขซีเรียลของอุปกรณ์:
@Override public void run(TestInformation testInfo, ITestInvocationListener listener) throws DeviceNotAvailableException { CLog.i("Hello, TF World! I have device " + testInfo.getDevice().getSerialNumber()); }
ตอนนี้สร้างการแลกเปลี่ยนใหม่และตรวจสอบรายการอุปกรณ์:
tradefed.sh
tf> list devices Serial State Product Variant Build Battery 004ad9880810a548 Available mako mako JDQ39 100
จดหมายเลขซีเรียลที่แสดงเป็น Available ; นั่นคืออุปกรณ์ที่ควรจัดสรรให้กับ 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 Listener ซึ่งเขียนผลการทดสอบลงในไฟล์ 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>
ตอนนี้สร้างการแลกเปลี่ยนใหม่และรันตัวอย่าง 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>
คุณยังสามารถเขียน Listener คำขอที่คุณกำหนดเองได้ โดยเพียงแค่ต้องใช้อินเทอร์เฟซ ITestInvocationListener
Tradefed รองรับ Listener คำขอหลายรายการ ดังนั้นคุณจึงสามารถส่งผลการทดสอบไปยังปลายทางอิสระหลายแห่งได้ ในการดำเนินการนี้ เพียงระบุแท็ก <result_reporter>
หลายแท็กในการกำหนดค่าของคุณ
สิ่งอำนวยความสะดวกในการบันทึก (D, I, R)
สิ่งอำนวยความสะดวกการบันทึกของ TF รวมถึงความสามารถในการ:
- บันทึกบันทึกจากอุปกรณ์ (หรือที่เรียกว่าอุปกรณ์ logcat)
- บันทึกบันทึกจากเฟรมเวิร์กของสหพันธ์การค้าที่ทำงานบนเครื่องโฮสต์ (หรือที่เรียกว่าบันทึกของโฮสต์)
กรอบงาน TF จะจับ logcat จากอุปกรณ์ที่จัดสรรโดยอัตโนมัติและส่งไปยัง Listener การร้องขอเพื่อประมวลผล จากนั้น XmlResultReporter
จะบันทึก logcat ของอุปกรณ์ที่บันทึกเป็นไฟล์
บันทึกโฮสต์ TF ได้รับการรายงานโดยใช้ CLog wrapper สำหรับคลาส 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 อีกครั้ง คุณจะเห็นข้อความบันทึกบน 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 …
ข้อความบันทึกระบุเส้นทางของบันทึกโฮสต์ ซึ่งเมื่อดูแล้วควรมีข้อความบันทึก 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
ในการเข้าร่วม คลาสอ็อบเจ็กต์การกำหนดค่าจะใช้คำอธิบายประกอบ @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="">
ทดสอบโดยใช้ 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! ฉันมีอุปกรณ์ …' หยุดแสดงบน stdout หลังจากที่เราเปลี่ยนมาใช้ FileLogger
คุณสามารถเพิ่มความละเอียดของการบันทึกเป็น stdout ได้โดยส่งผ่านใน --log-level-display
arg --log-level-display
ลองตอนนี้แล้วคุณจะเห็นข้อความบันทึก 'ฉันมีอุปกรณ์' ปรากฏขึ้นอีกครั้งใน 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 ที่ใช้แพลตฟอร์ม Android โดยมี "สหพันธ์การค้า" อยู่ในหัวเรื่องข้อความ