ตัวอย่างการทดสอบแบบวัดคุมด้วยตนเอง

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

ซึ่งหมายความว่าการทดสอบการใช้เครื่องมือจะแทรกตัวเองเข้าไปในเฟรมเวิร์กของ Android หรือที่เรียกว่าเซิร์ฟเวอร์ระบบเพื่อการดำเนินการไม่ได้ หากต้องการทดสอบเฟรมเวิร์ก Android โค้ดทดสอบจะเรียกใช้ได้เฉพาะแพลตฟอร์ม API สาธารณะหรือแพลตฟอร์มที่เปิดเผยโดยใช้ภาษาคำจำกัดความอินเทอร์เฟซ Android (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 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 ใช้เพื่อระบุแอปพลิเคชัน (หรือในแง่นี้ก็คือแอปพลิเคชันทดสอบของคุณ) ผู้ใช้แต่ละรายในระบบ สามารถติดตั้งแอปพลิเคชันที่มีชื่อแพ็กเกจนั้นได้ 1 รายการเท่านั้น

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

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

android:sharedUserId="android.uid.system"

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

  • สิทธิ์หรือ 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 ถือว่าเพียงพอแล้ว ดูรายละเอียดได้ที่การกำหนดค่าการทดสอบแบบง่าย

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

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

การกําหนดค่าการทดสอบสามารถระบุตัวเลือกการตั้งค่าอุปกรณ์พิเศษและอาร์กิวเมนต์เริ่มต้นเพื่อระบุคลาสการทดสอบ ดูตัวอย่างได้ที่ /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 ที่จะใช้ในการเรียกใช้การทดสอบ และส่งผ่านแพ็กเกจในอุปกรณ์ที่จะเรียกใช้และเฟรมเวิร์กโปรแกรมทดสอบ ซึ่งในกรณีนี้คือ 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 กับเมธอดเพื่อดําเนินการตั้งค่าก่อนเรียกใช้การทดสอบทั้งหมดในคลาสทดสอบ และปิดใช้งานหลังจากนั้น โปรดทราบว่าวิธีการตั้งค่าและเลิกใช้งานระดับคลาสต้องเป็นแบบคงที่ สำหรับวิธีการทดสอบ ไม่จำเป็นต้องขึ้นต้นชื่อวิธีการด้วย test อีกต่อไป ต่างจาก JUnit เวอร์ชันเก่า แต่ต้องกำกับเนื้อหาด้วย @Test ตามปกติแล้ว วิธีการทดสอบต้องเป็นแบบสาธารณะ ไม่ประกาศค่าที่แสดงผล ไม่รับพารามิเตอร์ และอาจแสดงข้อยกเว้น

การเข้าถึงคลาสการใช้เครื่องมือ

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

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

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

Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation()

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

สําหรับ Use Case ที่พบบ่อยที่สุด ให้ใช้ Atest

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