สร้างการทดสอบ 1 หน่วยในเครื่อง

การทดสอบในเครื่องจะทํางานบนเวิร์กสเตชันของคุณเองโดยตรง ไม่ใช่ในอุปกรณ์หรือโปรแกรมจําลอง Android ด้วยเหตุนี้ ระบบจึงใช้ Java Virtual Machine (JVM) ในเครื่องของคุณ แทนที่จะใช้อุปกรณ์ Android เพื่อทำการทดสอบ การทดสอบในเครื่องช่วยให้คุณประเมินตรรกะของแอปได้เร็วขึ้น อย่างไรก็ตาม การที่โต้ตอบกับเฟรมเวิร์ก Android ไม่ได้จะจํากัดประเภทการทดสอบที่คุณทําได้

การทดสอบหน่วยจะยืนยันลักษณะการทํางานของโค้ดส่วนเล็กๆ ซึ่งเป็นหน่วยที่อยู่ภายใต้การทดสอบ โดยการเรียกใช้โค้ดและตรวจสอบผลลัพธ์

การทดสอบ 1 หน่วยมักจะทำได้ง่าย แต่การตั้งค่าอาจทำให้เกิดปัญหาเมื่อหน่วย อยู่ระหว่างทดสอบไม่ได้ออกแบบโดยคำนึงถึงความสามารถในการทดสอบ

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

หากต้องการดูข้อมูลเกี่ยวกับกลยุทธ์การทดสอบหน่วยทั่วไปใน Android โปรดอ่านสิ่งที่ต้องทดสอบ

ตำแหน่งการทดสอบในพื้นที่

โดยค่าเริ่มต้น ไฟล์ต้นฉบับสำหรับการทดสอบหน่วยในเครื่องจะอยู่ใน module-name/src/test/ ไดเรกทอรีนี้มีอยู่แล้วเมื่อคุณสร้างโปรเจ็กต์ใหม่โดยใช้ Android Studio

การเพิ่มการพึ่งพาการทดสอบ

นอกจากนี้ คุณยังต้องกําหนดค่าการพึ่งพาการทดสอบสําหรับโปรเจ็กต์เพื่อใช้ API มาตรฐานที่เฟรมเวิร์กการทดสอบ JUnit มีให้

โดยเปิดไฟล์ build.gradle ของโมดูลแอป แล้วระบุไลบรารีต่อไปนี้เป็น Dependency ใช้ฟังก์ชัน testImplementation เพื่อระบุ ที่ใช้กับชุดแหล่งที่มาทดสอบในเครื่อง ไม่ใช่แอปพลิเคชัน

dependencies {
  // Required -- JUnit 4 framework
  testImplementation "junit:junit:$jUnitVersion"
  // Optional -- Robolectric environment
  testImplementation "androidx.test:core:$androidXTestVersion"
  // Optional -- Mockito framework
  testImplementation "org.mockito:mockito-core:$mockitoVersion"
  // Optional -- mockito-kotlin
  testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion"
  // Optional -- Mockk framework
  testImplementation "io.mockk:mockk:$mockkVersion"
}

สร้างชั้นเรียนการทดสอบหน่วยท้องถิ่น

คุณเขียนคลาสการทดสอบ 1 หน่วยในเครื่องเป็นคลาสทดสอบ JUnit 4

โดยสร้างคลาสที่มีเมธอดทดสอบอย่างน้อย 1 รายการ ซึ่งโดยปกติจะอยู่ในไฟล์ module-name/src/test/ วิธีการทดสอบเริ่มต้นด้วยคำอธิบายประกอบ @Test และ มีโค้ดสำหรับใช้งานและตรวจสอบองค์ประกอบด้านเดียวที่ ที่คุณต้องการทดสอบ

ตัวอย่างต่อไปนี้สาธิตวิธีใช้คลาสการทดสอบ 1 หน่วยในเครื่อง วิธีการทดสอบemailValidator_correctEmailSimple_returnsTrue()ความพยายามเพื่อยืนยัน isValidEmail() ซึ่งเป็นเมธอดภายในแอป ฟังก์ชันทดสอบจะแสดงผล "true" หาก isValidEmail() แสดงผลเป็น "true" ด้วย

Kotlin


import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test

class EmailValidatorTest {
  @Test fun emailValidator_CorrectEmailSimple_ReturnsTrue() {
    assertTrue(EmailValidator.isValidEmail("name@email.com"))
  }

}

Java


import org.junit.Test;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

class EmailValidatorTest {
  @Test
  public void emailValidator_CorrectEmailSimple_ReturnsTrue() {
    assertTrue(EmailValidator.isValidEmail("name@email.com"));
  }
}

คุณควรสร้างการทดสอบที่อ่านง่ายซึ่งประเมินว่าคอมโพเนนต์ในแอปแสดงผลลัพธ์ตามที่คาดไว้หรือไม่ เราขอแนะนำให้คุณใช้ไลบรารีการยืนยัน เป็น junit.Assert, Hamcrest หรือ ความจริง ข้อมูลโค้ดด้านบนเป็นตัวอย่างวิธีใช้ junit.Assert

ไลบรารี Android ที่จำลองได้

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

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

การจำลองทรัพยากร Dependency ของ Android

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

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

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

  1. รวมทรัพยากร Dependency ของไลบรารี Mockito ไว้ในไฟล์ build.gradle เป็น ตามที่อธิบายไว้ในหัวข้อตั้งค่าสภาพแวดล้อมการทดสอบของคุณ
  2. เพิ่มการกำกับเนื้อหา @RunWith(MockitoJUnitRunner.class) ที่จุดเริ่มต้นของคำจำกัดความคลาสการทดสอบหน่วย คําอธิบายประกอบนี้บอกโปรแกรมรันทดสอบ Mockito ให้ตรวจสอบว่าการใช้เฟรมเวิร์กถูกต้อง และลดความซับซ้อนในการเริ่มต้นวัตถุจำลอง
  3. หากต้องการสร้างออบเจ็กต์จำลองสําหรับการพึ่งพา Android ให้เพิ่มแอตทริบิวต์ @Mock ก่อนการประกาศฟิลด์
  4. หากต้องการจำลองลักษณะการทํางานของ Dependency ให้ระบุเงื่อนไขและค่าที่แสดงผลเมื่อเป็นไปตามเงื่อนไขโดยใช้เมธอด when() และ thenReturn()

ตัวอย่างต่อไปนี้แสดงวิธีสร้างการทดสอบ 1 หน่วยที่ใช้ออบเจ็กต์การจําลอง Context ใน Kotlin ซึ่งสร้างด้วย Mockito-Kotlin

import android.content.Context
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.junit.MockitoJUnitRunner
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock

private const val FAKE_STRING = "HELLO WORLD"

@RunWith(MockitoJUnitRunner::class)
class MockedContextTest {

  @Mock
  private lateinit var mockContext: Context

  @Test
  fun readStringFromContext_LocalizedString() {
    // Given a mocked Context injected into the object under test...
    val mockContext = mock<Context> {
        on { getString(R.string.name_label) } doReturn FAKE_STRING
    }

    val myObjectUnderTest = ClassUnderTest(mockContext)

    // ...when the string is returned from the object under test...
    val result: String = myObjectUnderTest.getName()

    // ...then the result should be the expected one.
    assertEquals(result, FAKE_STRING)
  }
}

ดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้เฟรมเวิร์กของ Mockito ได้ที่ Mockito API การอ้างอิง และคลาส SharedPreferencesHelperTest ใน ตัวอย่างโค้ด หรือลองใช้ Android Testing Codelab

ข้อผิดพลาด: "เมธอด ... ไม่ได้มีการเลียนแบบ"

ไลบรารี Android ที่จำลองขึ้นมาจะให้การยกเว้น หากคุณพยายามเข้าถึง ด้วยข้อความ Error: "Method ... not mocked

หากข้อยกเว้นที่ใส่ก่อให้เกิดปัญหาต่อการทดสอบของคุณ คุณสามารถเปลี่ยน เพื่อให้เมธอดแสดงผลเป็น null หรือ 0 แทน ทั้งนี้ขึ้นอยู่กับ ประเภทการแสดงผล โดยให้เพิ่มการกําหนดค่าต่อไปนี้ในไฟล์ build.gradle ระดับบนสุดของโปรเจ็กต์ใน Groovy

android {
  ...
  testOptions {
    unitTests.returnDefaultValues = true
  }