การจำลองด้วย Mockito
แยก dependency ด้วย Mockito และ MockK กำหนดค่าผลลัพธ์จำลอง ตรวจสอบการโต้ตอบ ดักจับอาร์กิวเมนต์ และใช้สายลับสำหรับการจำลองบางส่วน
การจำลองด้วย Mockito เป็นบทเรียน Android Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Android Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Android Academy มีบทเรียนทั้งหมด 4 บทเรียน
Mocking คืออะไร
mock คือออบเจ็กต์จำลองที่ใช้แทนการพึ่งพาจริงในการทดสอบ ต่างจาก Fake (การนำไปใช้งานในหน่วยความจำที่ทำงานได้จริง) mock จะ:
- ถูกสร้างโดยอัตโนมัติด้วยไลบรารี
- บันทึกว่าเรียกเมธอดใดและส่งอาร์กิวเมนต์ใดไป
- คืนค่าตามที่คุณกำหนด (การกำหนดพฤติกรรมจำลอง)
- ให้คุณ ตรวจสอบ การโต้ตอบหลังการทดสอบ
การตั้งค่า Mockito
เพิ่ม Mockito และ MockK (ทางเลือกที่ออกแบบมาสำหรับ Kotlin) ลงใน app/build.gradle:
// app/build.gradle:
testImplementation 'org.mockito:mockito-core:5.10.0'
testImplementation 'org.mockito.kotlin:mockito-kotlin:5.2.1'
// MockK (Kotlin-idiomatic alternative to Mockito):
testImplementation 'io.mockk:mockk:1.13.10'การสร้าง Mock
สร้าง mock ด้วย mock() หรือคำอธิบายประกอบ @Mock:
import org.mockito.kotlin.*
interface UserApi {
suspend fun fetchUsers(): List<User>
suspend fun deleteUser(id: Int)
}
class RepositoryTest {
// Option 1: create inline
private val api: UserApi = mock()
// Option 2: use annotation + MockitoJUnit4Runner
@Mock lateinit var api2: UserApi
@get:Rule
val mockitoRule = MockitoJUnit.rule()
}การกำหนดพฤติกรรมจำลอง — กำหนดค่าที่คืนกลับ
ใช้ whenever(mock.method()).thenReturn(value) เพื่อกำหนดค่าที่ mock จะคืนกลับ:
val api: UserApi = mock()
// Stub a return value:
whenever(api.fetchUsers()).thenReturn(
listOf(User(1, "Alice"), User(2, "Bob"))
)
// Stub an exception:
whenever(api.fetchUsers()).thenThrow(RuntimeException("Network error"))
// Return different values on consecutive calls:
whenever(api.fetchUsers())
.thenReturn(emptyList()) // first call
.thenReturn(listOf(User(1, "Alice"))) // second callverify() — ตรวจสอบการโต้ตอบ
ใช้ verify() เพื่อตรวจสอบยืนยันว่าเมธอดถูกเรียก และถูกเรียกกี่ครั้ง:
val api: UserApi = mock()
val repo = UserRepository(api)
repo.refreshUsers()
// Verify that fetchUsers() was called exactly once:
verify(api).fetchUsers()
// Verify called with specific argument:
repo.deleteUser(42)
verify(api).deleteUser(42)
// Verify called exactly 3 times:
verify(api, times(3)).fetchUsers()
// Verify never called:
verify(api, never()).deleteUser(any())ArgumentCaptor
ArgumentCaptor จับอาร์กิวเมนต์ที่ส่งให้เมธอดของ mock เพื่อให้คุณตรวจสอบค่าได้:
val api: UserApi = mock()
val captor = argumentCaptor<User>()
val repo = UserRepository(api)
repo.saveUser(User(1, "Alice"))
verify(api).saveUser(captor.capture())
val captured = captor.firstValue
assertEquals(1, captured.id)
assertEquals("Alice", captured.name)MockK — การจำลองที่ออกแบบมาสำหรับ Kotlin
MockK ออกแบบมาสำหรับ Kotlin และรองรับฟังก์ชันส่วนขยาย โครูทีน และออบเจ็กต์โดยตรง:
import io.mockk.*
val api = mockk<UserApi>()
// Stub:
every { api.fetchUsers() } returns listOf(User(1, "Alice"))
// Stub suspend function:
coEvery { api.fetchUsers() } returns listOf(User(1, "Alice"))
// Verify:
val repo = UserRepository(api)
runBlocking { repo.refresh() }
coVerify { api.fetchUsers() }การจำลองโครูทีนด้วย MockK
ใช้ coEvery และ coVerify กับฟังก์ชัน suspend:
val api = mockk<UserApi>()
// Stub suspend function:
coEvery { api.fetchUsers() } returns listOf(User(1, "Alice"))
coEvery { api.deleteUser(any()) } just Runs // returns Unit
// Test:
runTest {
val repo = UserRepository(api)
repo.refresh()
coVerify(exactly = 1) { api.fetchUsers() }
coVerify(exactly = 0) { api.deleteUser(any()) }
}Spy — การจำลองบางส่วน
spy จะครอบออบเจ็กต์จริงไว้ โดยค่าเริ่มต้นจะเรียกเมธอดจริง เว้นแต่จะกำหนดทับ:
// Mockito Spy:
val realList = mutableListOf("a", "b", "c")
val spyList = spy(realList)
// Real method called:
spyList.add("d")
assertEquals(4, spyList.size) // real add() was called
// Override specific method:
doReturn(99).`when`(spyList).size
assertEquals(99, spyList.size) // overridden
// MockK Spy:
val spyObj = spyk(RealService())
every { spyObj.expensiveCall() } returns "fake result"ควรใช้ Mock หรือ Fake เมื่อใด
แนวทางเชิงปฏิบัติ:
- ใช้ Fake เมื่อต้องการการนำไปใช้งานในหน่วยความจำที่ทำงานได้จริง (DAO, repository) — อ่านง่ายกว่าและไม่ต้องใช้ไลบรารี
- ใช้ Mock เมื่อต้องตรวจสอบว่าเมธอดหนึ่งถูกเรียกด้วยอาร์กิวเมนต์ที่กำหนด (เหตุการณ์การวิเคราะห์ข้อมูล, การเรียก API)
- หลีกเลี่ยงการใช้ mock มากเกินไป — หากจำลองทุกอย่าง การทดสอบจะตรวจสอบ mock ไม่ใช่ตรรกะของคุณ
ข้อผิดพลาดที่พบบ่อย
ข้อควรระวังในการใช้ mocking:
- จำลองออบเจ็กต์ค่า — ควรจำลองอินเทอร์เฟซ/สิ่งนามธรรม ไม่ใช่คลาสข้อมูล
- จำลองลึกเกินไป — หากต้องใช้ mock 5 ตัวในการทดสอบเดียว โค้ดก็เชื่อมโยงกันแน่นเกินไป
- ไม่ตรวจสอบ เมื่อการโต้ตอบมีความสำคัญ — อย่ากำหนดพฤติกรรมจำลองอย่างเดียว ต้องตรวจสอบด้วย
- ค่าเริ่มต้นของ Mockito + Kotlin — พารามิเตอร์ Kotlin ไม่เป็น null โดยค่าเริ่มต้น ให้ใช้
mockito-kotlinหรือ MockK เพื่อหลีกเลี่ยงปัญหา null ที่คาดไม่ถึง
การจำลองออบเจ็กต์และ Companion Object
MockK สามารถจำลองออบเจ็กต์ Kotlin และ companion object ได้ ซึ่ง Mockito ทำไม่ได้:
object DateProvider {
fun today(): String = "2024-01-01"
}
// In test:
mockkObject(DateProvider)
every { DateProvider.today() } returns "2099-12-31"
val result = DateProvider.today()
assertEquals("2099-12-31", result)
// Restore after test:
unmockkObject(DateProvider)ตรวจสอบความเข้าใจ
verify() มีจุดประสงค์ใดในการทดสอบด้วย Mockito หรือ MockK
ทบทวน: การจำลองด้วย Mockito และ MockK
Mock ช่วยแยกและตรวจสอบพฤติกรรมได้:
mock()/mockk()— สร้าง mock จากอินเทอร์เฟซหรือคลาสwhenever(...).thenReturn(...)/every { } returns ...— กำหนดค่าที่คืนกลับcoEvery/coVerify— สำหรับฟังก์ชัน suspend ของ Kotlin (MockK)verify(mock).method(args)— ตรวจสอบว่าเมธอดถูกเรียกArgumentCaptor— จับและตรวจสอบอาร์กิวเมนต์spy()/spyk()— จำลองออบเจ็กต์จริงบางส่วน- ควรใช้ Fake สำหรับข้อมูล และใช้ Mock เพื่อตรวจสอบพฤติกรรม
ถัดไป: การทดสอบ UI ด้วย Espresso
คำถามที่พบบ่อย
บทเรียน “การจำลองด้วย Mockito” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การจำลองด้วย Mockito” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Android Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Android Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การจำลองด้วย Mockito”
แยก dependency ด้วย Mockito และ MockK กำหนดค่าผลลัพธ์จำลอง ตรวจสอบการโต้ตอบ ดักจับอาร์กิวเมนต์ และใช้สายลับสำหรับการจำลองบางส่วน คุณปฏิบัติ Android Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Android Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Android Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “การจำลองด้วย Mockito” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Android Academy นี้ได้ไหม
ได้ บทเรียน Android Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การทดสอบหน่วยด้วย JUnit
- การจำลองด้วย Mockito
- การทดสอบส่วนติดต่อผู้ใช้ด้วย Espresso
- การดีบักและการวิเคราะห์ประสิทธิภาพ