การทดสอบในเครื่องจะทำงานโดยตรงในเวิร์กสเตชันของคุณเอง แทนที่จะเป็นอุปกรณ์หรือโปรแกรมจำลอง Android ด้วยเหตุนี้ จึงใช้ Java Virtual Machine (JVM) ในเครื่องแทนอุปกรณ์ Android เพื่อทำการทดสอบ การทดสอบในเครื่องช่วยให้คุณประเมินตรรกะของแอปได้รวดเร็วยิ่งขึ้น อย่างไรก็ตาม การไม่สามารถโต้ตอบกับเฟรมเวิร์ก Android จะสร้างข้อจำกัดในประเภทการทดสอบที่คุณเรียกใช้ได้
Unit Test จะยืนยันลักษณะการทำงานของโค้ดส่วนเล็กๆ ซึ่งก็คือ Unit ที่อยู่ระหว่างการทดสอบ โดยจะเรียกใช้โค้ดนั้นและตรวจสอบผลลัพธ์
โดยปกติแล้ว Unit Test จะเป็นเรื่องง่าย แต่การตั้งค่าอาจเป็นปัญหาได้เมื่อหน่วยที่ทดสอบไม่ได้ออกแบบมาโดยคำนึงถึงความสามารถในการทดสอบ
- โค้ดที่ต้องการยืนยันต้องเข้าถึงได้จากการทดสอบ ตัวอย่างเช่น คุณไม่สามารถทดสอบเมธอดส่วนตัวได้โดยตรง แต่คุณจะทดสอบคลาสโดยใช้ API สาธารณะแทน
- หากต้องการเรียกใช้ Unit Test ในการแยก คุณต้องแทนที่ทรัพยากร Dependency ของหน่วยที่อยู่ระหว่างการทดสอบด้วยคอมโพเนนต์ที่คุณควบคุม เช่น ตัวจำลองหรือตัวทดสอบอื่นๆ ปัญหานี้จะสร้างปัญหาเป็นพิเศษหากโค้ดของคุณขึ้นอยู่กับเฟรมเวิร์ก Android
หากต้องการดูข้อมูลเกี่ยวกับกลยุทธ์การทำ Unit Test ทั่วไปใน Android โปรดอ่านสิ่งที่ต้องทดสอบ
ตำแหน่งการทดสอบในพื้นที่
โดยค่าเริ่มต้น ไฟล์ต้นฉบับสำหรับการทำ Unit Test ในเครื่องจะอยู่ใน module-name/src/test/ ไดเรกทอรีนี้มีอยู่แล้วเมื่อคุณสร้างโปรเจ็กต์ใหม่โดยใช้ Android Studio
การเพิ่มทรัพยากร Dependency สำหรับการทดสอบ
นอกจากนี้ คุณยังต้องกำหนดค่าทรัพยากร Dependency ของการทดสอบสำหรับโปรเจ็กต์เพื่อใช้ 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"
}
สร้างคลาส Unit Test ในเครื่อง
คุณเขียนคลาส Unit Test ในเครื่องเป็นคลาสทดสอบ JUnit 4
โดยสร้างคลาสที่มีเมธอดทดสอบอย่างน้อย 1 รายการ ซึ่งมักจะอยู่ใน module-name/src/test/ เมธอดทดสอบจะขึ้นต้นด้วยคำอธิบายประกอบ @Test และมีโค้ดสำหรับฝึกและยืนยันแง่มุมเดียวของคอมโพเนนต์ที่คุณต้องการทดสอบ
ตัวอย่างต่อไปนี้แสดงวิธีใช้คลาส Unit Test ในเครื่อง เมธอดทดสอบ emailValidator_correctEmailSimple_returnsTrue()attempts to verify
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 หรือ Truth ข้อมูลโค้ดด้านบนเป็นตัวอย่างวิธีใช้ junit.Assert
ไลบรารี Android ที่จำลองได้
เมื่อคุณเรียกใช้ Unit Test ในเครื่อง ปลั๊กอิน Android Gradle จะรวมไลบรารีที่มี API ทั้งหมดของเฟรมเวิร์ก Android ซึ่งถูกต้องตามเวอร์ชันที่ใช้ในโปรเจ็กต์ ไลบรารีนี้มีเมธอดและคลาสสาธารณะทั้งหมดของ API เหล่านั้น แต่โค้ดภายในเมธอดถูกนำออกแล้ว หากมีการเข้าถึงเมธอดใดๆ การทดสอบจะแสดงข้อยกเว้น
ซึ่งจะช่วยให้สร้างการทดสอบในเครื่องได้เมื่ออ้างอิงคลาสในเฟรมเวิร์ก Android เช่น Context ที่สำคัญกว่านั้นคือช่วยให้คุณใช้เฟรมเวิร์กจำลองกับคลาส Android ได้
การจำลองทรัพยากร Dependency ของ Android
ปัญหาที่พบได้ทั่วไปคือการพบว่าคลาสใช้ทรัพยากรสตริง คุณสามารถรับทรัพยากรสตริงได้โดยเรียกใช้เมธอด getString() ในคลาส Context อย่างไรก็ตาม การทดสอบในเครื่องไม่สามารถใช้ Context หรือเมธอดใดๆ ของคลาสนี้ได้ เนื่องจากเป็นของเฟรมเวิร์ก Android ตามหลักการแล้ว การเรียกใช้ getString() ควรย้ายออกจากคลาส แต่ก็อาจทำไม่ได้เสมอไป วิธีแก้ไขคือสร้างม็อกหรือสตับของ Context ที่แสดงผลค่าเดียวกันเสมอเมื่อมีการเรียกใช้เมธอด getString()
ด้วยไลบรารี Android ที่จำลองได้และเฟรมเวิร์กจำลอง เช่น Mockito หรือ MockK คุณสามารถตั้งโปรแกรมลักษณะการทำงานของการจำลองคลาส Android ในการทดสอบหน่วยได้
หากต้องการเพิ่มออบเจ็กต์จำลองลงใน Unit Test ในเครื่องโดยใช้ Mockito ให้ทำตามรูปแบบการเขียนโปรแกรมต่อไปนี้
- รวมทรัพยากร Dependency ของไลบรารี Mockito ไว้ในไฟล์
build.gradleตามที่อธิบายไว้ในตั้งค่าสภาพแวดล้อมการทดสอบ - เพิ่มคำอธิบายประกอบ
@RunWith(MockitoJUnitRunner.class)ที่จุดเริ่มต้นของคำจำกัดความคลาส Unit Test คำอธิบายประกอบนี้จะบอกให้ Mockito Test Runner ตรวจสอบว่าการใช้งานเฟรมเวิร์กของคุณถูกต้อง และลดความซับซ้อนของการเริ่มต้นออบเจ็กต์จำลอง - หากต้องการสร้างออบเจ็กต์จำลองสำหรับการขึ้นต่อกันของ Android ให้เพิ่มคำอธิบายประกอบ
@Mockก่อนการประกาศฟิลด์ - หากต้องการสร้างสตับสำหรับลักษณะการทำงานของทรัพยากร Dependency คุณสามารถระบุเงื่อนไขและค่าที่แสดงผลเมื่อตรงตามเงื่อนไขโดยใช้เมธอด
when()และthenReturn()
ตัวอย่างต่อไปนี้แสดงวิธีสร้าง Unit Test ที่ใช้ออบเจ็กต์ 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 ได้ที่เอกสารอ้างอิง API ของ Mockito และคลาส SharedPreferencesHelperTest ในโค้ดตัวอย่าง นอกจากนี้ ให้ลองใช้ Codelab การทดสอบ Android ด้วย
ข้อผิดพลาด: "Method ... not mocked"
ไลบรารี Android ที่จำลองได้จะแสดงข้อยกเว้นหากคุณพยายามเข้าถึงเมธอดใดๆ ของไลบรารีด้วยข้อความ Error: "Method ... not mocked
หากข้อยกเว้นที่แสดงขึ้นเป็นปัญหาสำหรับการทดสอบ คุณสามารถเปลี่ยนลักษณะการทำงานเพื่อให้เมธอดแสดงผลเป็น Null หรือ 0 แทน โดยขึ้นอยู่กับประเภทการแสดงผล โดยเพิ่มการกำหนดค่าต่อไปนี้ในไฟล์ build.gradle ระดับบนสุดของโปรเจ็กต์ใน Groovy
android {
...
testOptions {
unitTests.returnDefaultValues = true
}