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

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

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

แพ็คเกจแอปพลิเคชันทดสอบในหมวดหมู่นี้อาจ:

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

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

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

ขอแนะนำให้เรียกดูรหัสก่อนเพื่อรับความประทับใจก่อนดำเนินการต่อ

การตัดสินใจเลือกตำแหน่งต้นทาง

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

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

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

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

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

ไฟล์รายการ

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

ก่อนดำเนินการต่อ ขอแนะนำให้อ่าน ภาพรวมของ App Manifest ก่อน

สิ่งนี้ให้ภาพรวมของส่วนประกอบพื้นฐานของไฟล์รายการและฟังก์ชันการทำงาน ดูตัวอย่างได้ที่ platform_testing/tests/example/instrumentation/AndroidManifest.xml

ภาพรวมอยู่ที่นี่เพื่อความสะดวก:

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

    <application/>

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

</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 ระดับบนสุดในแอปพลิเคชันหรือการทดสอบที่เหมือนกับชื่อแพ็กเกจแอปพลิเคชัน

android:sharedUserId="android.uid.system"

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

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

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

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

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

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

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

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

ข้อ สำคัญ : วิธีการทดสอบนั้นจะมีคำอธิบายประกอบด้วย @Test คำอธิบายประกอบ และโปรดทราบว่าสำหรับการทดสอบที่ดำเนินการผ่าน APCT จะต้องใส่คำอธิบายประกอบด้วยขนาดการทดสอบ: ตัวอย่างวิธีการใส่คำอธิบายประกอบ testHelloWorld เป็น @SmallTest คำอธิบายประกอบอาจนำไปใช้ที่ขอบเขตเมธอดหรือขอบเขตคลาส

การเข้าถึง instrumentation

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

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

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

Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation()

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

สำหรับกรณีการใช้งานทั่วไป ให้จ้าง Atest

สำหรับกรณีที่ซับซ้อนมากขึ้นและต้องการการปรับแต่งที่หนักขึ้น ให้ทำตาม คำแนะนำการใช้เครื่องมือ