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

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

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

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

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

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

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

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

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

การเข้าถึงคลาสเครื่องมือวัด

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

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

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

Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation()

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

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

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