ตัวอย่างการทดสอบที่มีเครื่องมือวัดของตัวเอง

เมื่อเริ่มการทดสอบการวัดคุม ระบบจะรีสตาร์ทแพ็กเกจเป้าหมาย พร้อมกับโค้ดการวัดคุมที่แทรกไว้และเริ่มต้นการดำเนินการ ข้อยกเว้นอย่างหนึ่งคือแพ็กเกจเป้าหมายที่นี่ต้องไม่ใช่เฟรมเวิร์กแอปพลิเคชัน Android เอง เช่น แพ็กเกจ android เนื่องจากจะทำให้เกิดสถานการณ์ที่ขัดแย้งกันซึ่งเฟรมเวิร์ก Android จะต้องรีสตาร์ท ซึ่งเป็นสิ่งที่รองรับฟังก์ชันของระบบ รวมถึงการตรวจสอบเอง

ซึ่งหมายความว่าการทดสอบด้วยเครื่องมือไม่สามารถแทรกตัวเองลงในเฟรมเวิร์ก Android หรือที่เรียกว่าเซิร์ฟเวอร์ระบบเพื่อดำเนินการได้ หากต้องการทดสอบเฟรมเวิร์ก Android โค้ดทดสอบจะเรียกใช้ได้เฉพาะ API สาธารณะ หรือ API ที่เปิดเผย โดยใช้ Android Interface Definition Language AIDL ที่มีอยู่ในโครงสร้างแหล่งที่มาของแพลตฟอร์ม สําหรับการทดสอบหมวดหมู่นี้ การกำหนดเป้าหมายไปยังแพ็กเกจใดแพ็กเกจหนึ่งไม่มีความหมาย ดังนั้นจึงเป็นเรื่องปกติที่การวัดผลดังกล่าว จะประกาศเพื่อกำหนดเป้าหมายแพ็กเกจแอปพลิเคชันทดสอบของตัวเอง ตามที่ กำหนดไว้ในแท็ก <manifest> ของ AndroidManifest.xml

ทั้งนี้แพ็กเกจแอปพลิเคชันทดสอบในหมวดหมู่นี้อาจมีลักษณะดังต่อไปนี้ด้วย

  • กิจกรรมแบบกลุ่มที่จำเป็นสำหรับการทดสอบ
  • แชร์รหัสผู้ใช้กับระบบ
  • ต้องลงนามด้วยคีย์แพลตฟอร์ม
  • คอมไพล์กับแหล่งที่มาของเฟรมเวิร์กแทน SDK สาธารณะ

บางครั้งเราเรียกการทดสอบเครื่องมือในหมวดหมู่นี้ว่า การวัดผลด้วยตนเอง ตัวอย่างการทดสอบการวัดผลด้วยตนเองใน แหล่งที่มาของแพลตฟอร์มมีดังนี้

ตัวอย่างที่กล่าวถึงในที่นี้คือการเขียนการทดสอบเครื่องมือใหม่โดยตั้งค่าแพ็กเกจเป้าหมาย ไว้ที่แพ็กเกจแอปพลิเคชันทดสอบของตัวเอง คู่มือนี้ใช้การทดสอบต่อไปนี้ เพื่อเป็นตัวอย่าง

เราขอแนะนำให้คุณเรียกดูโค้ดก่อนเพื่อดูภาพรวมคร่าวๆ ก่อนดำเนินการต่อ

กำหนดตำแหน่งต้นทาง

โดยปกติแล้ว ทีมของคุณจะมีรูปแบบที่กำหนดไว้แล้วสำหรับตำแหน่งที่จะเช็คอินโค้ดและตำแหน่งที่จะเพิ่มการทดสอบ ทีมส่วนใหญ่เป็นเจ้าของที่เก็บ Git เดียว หรือแชร์ที่เก็บกับทีมอื่นๆ แต่มีไดเรกทอรีย่อยเฉพาะที่มีซอร์สโค้ดของคอมโพเนนต์

สมมติว่าตำแหน่งรากของแหล่งที่มาของคอมโพเนนต์อยู่ที่ <component source root> คอมโพเนนต์ส่วนใหญ่จะมีโฟลเดอร์ src และ tests อยู่ภายใต้โฟลเดอร์นี้ และมีไฟล์เพิ่มเติมบางไฟล์ เช่น Android.mk (หรือแยกออกเป็นไฟล์ .mk เพิ่มเติม) ไฟล์ Manifest AndroidManifest.xml และไฟล์การกำหนดค่าการทดสอบ "AndroidTest.xml"

เนื่องจากคุณกำลังเพิ่มการทดสอบใหม่เอี่ยม คุณอาจต้องสร้างtestsไดเรกทอรีข้างคอมโพเนนต์src แล้วป้อนเนื้อหาลงในไดเรกทอรี

ในบางกรณี ทีมของคุณอาจมีโครงสร้างไดเรกทอรีเพิ่มเติมภายใต้ tests เนื่องจากต้องแพ็กเกจชุดการทดสอบต่างๆ ลงใน APK แต่ละรายการ และในกรณีนี้ คุณจะต้องสร้างไดเรกทอรีย่อยใหม่ภายใต้ tests

ไม่ว่าโครงสร้างจะเป็นอย่างไร คุณจะต้องป้อนข้อมูลในไดเรกทอรี tests หรือ ไดเรกทอรีย่อยที่สร้างขึ้นใหม่ด้วยไฟล์ที่คล้ายกับไฟล์ในไดเรกทอรี instrumentation ในการเปลี่ยนแปลง Gerrit ตัวอย่าง รายละเอียดของแต่ละ ไฟล์จะอธิบายในภายหลังในเอกสารนี้

ไฟล์ Manifest

เช่นเดียวกับโปรเจ็กต์แอป โมดูลการทดสอบเครื่องมือแต่ละโมดูลต้องมีไฟล์ Manifest ที่ชื่อ AndroidManifest.xml หากต้องการรวมไฟล์นี้โดยอัตโนมัติโดยใช้BUILD_PACKAGE core makefile ให้วางไฟล์นี้ไว้ข้างไฟล์Android.mkสำหรับโมดูลทดสอบ

หากไม่คุ้นเคยกับไฟล์ AndroidManifest.xml ให้อ่านภาพรวมของไฟล์ Manifest ของแอป

ตัวอย่างไฟล์ AndroidManifest.xml มีดังนี้

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  android:sharedUserId="android.uid.system"
  package="android.test.example.helloworld" >

    <application>
       <uses-library android:name="android.test.runner"/>
    </application>

    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
                     android:targetPackage="android.test.example.helloworld"
                     android:label="Hello World Test"/>

</manifest>

ข้อสังเกตบางประการเกี่ยวกับไฟล์ Manifest

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="android.test.example.helloworld" >

แอตทริบิวต์ package คือชื่อแพ็กเกจแอปพลิเคชัน ซึ่งเป็นตัวระบุที่ไม่ซ้ำกัน ที่เฟรมเวิร์กแอปพลิเคชัน Android ใช้เพื่อระบุแอปพลิเคชัน (หรือในบริบทนี้คือแอปพลิเคชันทดสอบของคุณ) ผู้ใช้แต่ละรายในระบบ จะติดตั้งแอปพลิเคชันที่มีชื่อแพ็กเกจนั้นได้เพียงแอปเดียว

นอกจากนี้ แอตทริบิวต์ package นี้ยังเหมือนกับที่ ComponentName#getPackageName() ส่งคืน และยังเหมือนกับที่คุณใช้เพื่อโต้ตอบกับคำสั่งย่อย pm ต่างๆ โดยใช้ adb shell

โปรดทราบว่าแม้ว่าโดยทั่วไปแล้วชื่อแพ็กเกจจะมีรูปแบบเดียวกันกับชื่อแพ็กเกจ Java แต่จริงๆ แล้วชื่อแพ็กเกจไม่ได้เกี่ยวข้องกับชื่อแพ็กเกจ Java มากนัก กล่าวอีกนัยหนึ่ง แพ็กเกจแอปพลิเคชัน (หรือการทดสอบ) อาจมีคลาสที่มีชื่อแพ็กเกจใดก็ได้ ในทางกลับกัน คุณอาจเลือกใช้ความเรียบง่ายและมีชื่อแพ็กเกจ Java ระดับบนสุดในแอปพลิเคชันหรือการทดสอบที่เหมือนกับชื่อแพ็กเกจแอปพลิเคชัน

android:sharedUserId="android.uid.system"

ซึ่งเป็นการประกาศว่าในเวลาที่ติดตั้ง ระบบควรให้รหัสผู้ใช้เดียวกันแก่ไฟล์ APK นี้ นั่นคือ ข้อมูลระบุตัวตนขณะรันไทม์ เช่นเดียวกับแพลตฟอร์มหลัก โปรดทราบว่าการดำเนินการนี้จะขึ้นอยู่กับว่า APK ได้รับการรับรองด้วยใบรับรองเดียวกันกับแพลตฟอร์มหลักหรือไม่ (ดู LOCAL_CERTIFICATE ในส่วนก่อนหน้า) แต่ทั้ง 2 อย่างนี้เป็นแนวคิดที่แตกต่างกัน

  • สิทธิ์หรือ API บางรายการได้รับการปกป้องด้วยลายเซ็น ซึ่งต้องใช้ ใบรับรองการลงนามเดียวกัน
  • สิทธิ์หรือ API บางอย่างต้องใช้systemข้อมูลประจำตัวผู้ใช้ของผู้เรียก ซึ่งกำหนดให้แพ็กเกจที่เรียกแชร์รหัสผู้ใช้กับ system หากเป็น แพ็กเกจแยกต่างหากจากแพลตฟอร์มหลัก
<uses-library android:name="android.test.runner" />

การทดสอบเครื่องมือทั้งหมดต้องมีข้อกำหนดนี้เนื่องจากคลาสที่เกี่ยวข้องจะ รวมอยู่ในไฟล์ไลบรารี JAR ของเฟรมเวิร์กแยกต่างหาก จึงต้องมีรายการ classpath เพิ่มเติม เมื่อเฟรมเวิร์กแอปพลิเคชันเรียกใช้แพ็กเกจการทดสอบ

android:targetPackage="android.test.example.helloworld"

คุณอาจสังเกตเห็นว่า targetPackage ที่นี่ประกาศเหมือนกับแอตทริบิวต์ package ที่ประกาศในแท็ก manifest ของไฟล์นี้ ดังที่กล่าวไว้ในพื้นฐานการทดสอบ การทดสอบเครื่องมือประเภทนี้มักมีไว้สำหรับทดสอบ API ของเฟรมเวิร์กการทดสอบ ดังนั้นจึงไม่ค่อยมีความหมายที่แอปพลิเคชันเป้าหมายเฉพาะจะมีแพ็กเกจอื่นนอกเหนือจากตัวมันเอง

ไฟล์การกำหนดค่าอย่างง่าย

โมดูลทดสอบใหม่แต่ละโมดูลต้องมีไฟล์กำหนดค่าเพื่อสั่งให้ ระบบบิลด์มีข้อมูลเมตาของโมดูล การขึ้นต่อกันในเวลาคอมไพล์ และคำสั่ง การแพ็กเกจ ในกรณีส่วนใหญ่ ตัวเลือกไฟล์ Blueprint ที่อิงตาม Soong จะเพียงพอ โปรดดูรายละเอียดที่การกำหนดค่าการทดสอบอย่างง่าย

ไฟล์การกำหนดค่าที่ซับซ้อน

สำหรับกรณีที่ซับซ้อนมากขึ้นเหล่านี้ คุณยังต้องเขียนไฟล์การกำหนดค่าการทดสอบสำหรับชุดทดสอบของ Android ซึ่งก็คือ Trade Federation ด้วย

การกำหนดค่าการทดสอบสามารถระบุตัวเลือกการตั้งค่าอุปกรณ์พิเศษและอาร์กิวเมนต์เริ่มต้นเพื่อจัดหาคลาสการทดสอบ ดูตัวอย่างได้ที่ /platform_testing/tests/example/instrumentation/AndroidTest.xml

เราได้รวมสแนปชอตไว้ที่นี่เพื่อความสะดวก

<configuration description="Runs sample instrumentation test.">
  <target_preparer class="com.android.tradefed.targetprep.TestFilePushSetup"/>
  <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
    <option name="test-file-name" value="HelloWorldTests.apk"/>
  </target_preparer>
  <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"/>
  <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"/>
  <option name="test-suite-tag" value="apct"/>
  <option name="test-tag" value="SampleInstrumentationTest"/>

  <test class="com.android.tradefed.testtype.AndroidJUnitTest">
    <option name="package" value="android.test.example.helloworld"/>
    <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
  </test>
</configuration>

ข้อสังเกตบางประการเกี่ยวกับไฟล์การกำหนดค่าการทดสอบ

<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
  <option name="test-file-name" value="HelloWorldTests.apk"/>
</target_preparer>

ซึ่งจะบอก Trade Federation ให้ติดตั้ง HelloWorldTests.apk ลงในอุปกรณ์เป้าหมาย โดยใช้ target_preparer ที่ระบุ นักพัฒนาแอปใน Trade Federation สามารถใช้ตัวเตรียมเป้าหมายหลายตัวเพื่อตรวจสอบว่า ตั้งค่าอุปกรณ์อย่างถูกต้องก่อนการทดสอบ

<test class="com.android.tradefed.testtype.AndroidJUnitTest">
  <option name="package" value="android.test.example.helloworld"/>
  <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
</test>

ซึ่งจะระบุคลาสการทดสอบของ Trade Federation ที่จะใช้ในการเรียกใช้การทดสอบและ ส่งผ่านในแพ็กเกจบนอุปกรณ์ที่จะเรียกใช้ รวมถึงเฟรมเวิร์ก Test Runner ซึ่งในกรณีนี้คือ JUnit

ดูข้อมูลเพิ่มเติมได้ที่ กำหนดค่าโมดูลทดสอบ

ฟีเจอร์ JUnit4

การใช้ไลบรารี android-support-test เป็นตัวเรียกใช้การทดสอบจะช่วยให้ใช้คลาสการทดสอบรูปแบบ JUnit4 ใหม่ได้ และการเปลี่ยนแปลง Gerrit ตัวอย่างมีการใช้ฟีเจอร์พื้นฐานบางอย่าง ดูตัวอย่างได้ที่ /platform_testing/tests/example/instrumentation/src/android/test/example/helloworld/HelloWorldTest.java

แม้ว่ารูปแบบการทดสอบมักจะเฉพาะเจาะจงสำหรับทีมคอมโพเนนต์ แต่ก็มีรูปแบบการใช้งานบางอย่างที่ มีประโยชน์โดยทั่วไป

@RunWith(JUnit4.class)
public class HelloWorldTest {

ความแตกต่างที่สำคัญใน JUnit4 คือไม่จำเป็นต้องให้การทดสอบสืบทอดจากคลาสการทดสอบฐานทั่วไปอีกต่อไป แต่คุณจะเขียนการทดสอบในคลาส Java ธรรมดาและใช้คำอธิบายประกอบเพื่อระบุการตั้งค่าและการจำกัดการทดสอบบางอย่างแทน ใน ตัวอย่างนี้ เรากำลังสั่งให้คลาสนี้ทำงานเป็นการทดสอบ JUnit4

    @BeforeClass
    public static void beforeClass() {
    ...
    @AfterClass
    public static void afterClass() {
    ...
    @Before
    public void before() {
    ...
    @After
    public void after() {
    ...
    @Test
    @SmallTest
    public void testHelloWorld() {
    ...

JUnit4 ใช้หมายเหตุ @Before และ @After กับเมธอดเพื่อดำเนินการ ตั้งค่าก่อนการทดสอบและล้างข้อมูลหลังการทดสอบ ในทำนองเดียวกัน JUnit4 จะใช้หมายเหตุประกอบ @BeforeClass และ @AfterClass ในเมธอดเพื่อทำการตั้งค่าก่อน เรียกใช้การทดสอบทั้งหมดในคลาสการทดสอบ และทำการล้างข้อมูลภายหลัง โปรดทราบว่าเมธอดการตั้งค่าและการล้างข้อมูลระดับคลาสต้องเป็นแบบคงที่ สำหรับเมธอดทดสอบ ไม่เหมือนกับ JUnit เวอร์ชันก่อนหน้า เมธอดทดสอบไม่จำเป็นต้องขึ้นต้นชื่อเมธอด ด้วย test อีกต่อไป แต่เมธอดทดสอบแต่ละรายการต้องมีคำอธิบายประกอบด้วย @Test เช่นเคย เมธอดการทดสอบต้องเป็นแบบสาธารณะ ไม่ประกาศค่าที่ส่งคืน ไม่รับพารามิเตอร์ และ อาจส่งข้อยกเว้น

การเข้าถึงคลาสการวัดประสิทธิภาพ

แม้ว่าตัวอย่าง "Hello World" ขั้นพื้นฐานจะไม่ได้ครอบคลุมถึงเรื่องนี้ แต่การทดสอบ Android มักจะต้องเข้าถึงอินสแตนซ์ Instrumentation ซึ่งเป็นอินเทอร์เฟซ API หลัก ที่ให้สิทธิ์เข้าถึงบริบทของแอปพลิเคชัน, API การทดสอบที่เกี่ยวข้องกับวงจรของกิจกรรม และอื่นๆ

เนื่องจากการทดสอบ JUnit4 ไม่จำเป็นต้องใช้คลาสฐานร่วมอีกต่อไป จึงไม่จำเป็นต้องรับอินสแตนซ์ Instrumentation ผ่าน InstrumentationTestCase#getInstrumentation() อีกต่อไป แต่ตัวเรียกใช้การทดสอบใหม่จะจัดการผ่าน InstrumentationRegistry แทน ซึ่งจะจัดเก็บการตั้งค่าตามบริบทและสภาพแวดล้อมที่สร้างขึ้นโดยเฟรมเวิร์กการวัด

หากต้องการเข้าถึงอินสแตนซ์ของคลาส Instrumentation ให้เรียกใช้เมธอดแบบคงที่ getInstrumentation() ในคลาส InstrumentationRegistry

Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation()

สร้างและทดสอบในเครื่อง

สำหรับกรณีการใช้งานที่พบบ่อยที่สุด ให้ใช้ Atest

สำหรับกรณีที่ซับซ้อนมากขึ้นซึ่งต้องมีการปรับแต่งที่หนักกว่า ให้ทำตามวิธีการติดตั้งเครื่องมือ