การทดสอบหน่วยด้วย JUnit
เขียนการทดสอบหน่วยที่รวดเร็วและเชื่อถือได้ด้วย JUnit 4 ใช้ @Test, @Before, @After และการตรวจสอบ ทดสอบ LiveData ด้วย InstantTaskExecutorRule และทดสอบโครูทีนด้วย runTest
การทดสอบหน่วยด้วย JUnit เป็นบทเรียน Android Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Android Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Android Academy มีบทเรียนทั้งหมด 4 บทเรียน
เหตุใดจึงควรเขียนการทดสอบ
การทดสอบไม่ใช่สิ่งฟุ่มเฟือย แต่เป็นตาข่ายนิรภัยของคุณ:
- ค้นหาข้อบกพร่องก่อนที่ผู้ใช้จะพบ
- ปรับโครงสร้างโค้ดได้อย่างมั่นใจ (หากการทดสอบผ่าน ก็แปลว่าไม่มีสิ่งใดเสียหาย)
- บันทึกพฤติกรรมที่ต้องการไว้เป็นเอกสาร
- ป้องกันการถดถอยเมื่อเพิ่มความสามารถใหม่
โค้ดที่ผ่านการทดสอบอย่างดียังมักออกแบบมาได้ดีกว่า หากทดสอบได้ยาก การออกแบบก็น่าจะเชื่อมโยงกันแน่นเกินไป
ประเภทของการทดสอบ Android
มีสองประเภท:
- การทดสอบหน่วย (โฟลเดอร์
test/) — ทำงานบน JVM โดยไม่ต้องใช้อุปกรณ์ รวดเร็ว ใช้ทดสอบตรรกะ Kotlin/Java ทั่วไป - การทดสอบบนอุปกรณ์ (โฟลเดอร์
androidTest/) — ทำงานบนอุปกรณ์หรืออีมูเลเตอร์ ช้ากว่า ใช้ทดสอบโค้ดเฉพาะของ Android (ฐานข้อมูล Room, UI)
ควรเลือกการทดสอบหน่วยสำหรับตรรกะทางธุรกิจ และใช้การทดสอบบนอุปกรณ์เฉพาะเมื่อต้องโต้ตอบกับ API ของ Android
การตั้งค่า JUnit 4
JUnit 4 มีมาให้โดยค่าเริ่มต้นในโปรเจกต์ Android ให้เพิ่มรายการต่อไปนี้ลงใน app/build.gradle:
// app/build.gradle:
dependencies {
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3'
testImplementation 'androidx.arch.core:core-testing:2.2.0' // for LiveData
}การทดสอบ JUnit ครั้งแรก
สร้างคลาสใน src/test/java/ และใส่คำอธิบายประกอบ @Test ให้เมธอดทดสอบ:
import org.junit.Test
import org.junit.Assert.*
class CalculatorTest {
private val calc = Calculator()
@Test
fun `addition returns correct sum`() {
val result = calc.add(2, 3)
assertEquals(5, result)
}
@Test
fun `division by zero throws exception`() {
assertThrows(ArithmeticException::class.java) {
calc.divide(10, 0)
}
}
}@Before และ @After
ใช้คำอธิบายประกอบวงจรชีวิตเพื่อเตรียมและล้างสถานะก่อนและหลังการทดสอบแต่ละครั้ง:
class UserRepositoryTest {
private lateinit var repo: UserRepository
private lateinit var fakeDao: FakeUserDao
@Before
fun setUp() {
fakeDao = FakeUserDao() // fresh instance before each test
repo = UserRepository(fakeDao)
}
@After
fun tearDown() {
fakeDao.clear() // clean up after each test
}
@Test
fun `getUsers returns all users`() {
fakeDao.insert(User(1, "Alice"))
fakeDao.insert(User(2, "Bob"))
assertEquals(2, repo.getUsers().size)
}
}การตรวจสอบยืนยันที่ใช้บ่อย
JUnit มีเมธอดสำหรับการตรวจสอบยืนยันใน Assert.*:
// Equality:
assertEquals(expected, actual)
assertNotEquals(unexpected, actual)
// Null:
assertNull(value)
assertNotNull(value)
// Boolean:
assertTrue(condition)
assertFalse(condition)
// Same object reference:
assertSame(expected, actual)
// Custom message on failure:
assertEquals("User ID should be 1", 1, user.id)
// Exception:
assertThrows(IllegalArgumentException::class.java) {
User(id = -1, name = "")
}การทดสอบ ViewModel
หากต้องการทดสอบ LiveData ให้เพิ่ม InstantTaskExecutorRule เพื่อให้ LiveData โพสต์ข้อมูลแบบพร้อมกัน:
class UserViewModelTest {
@get:Rule
val instantTaskRule = InstantTaskExecutorRule()
private val fakeRepo = FakeUserRepository()
private lateinit var viewModel: UserViewModel
@Before
fun setUp() {
viewModel = UserViewModel(fakeRepo)
}
@Test
fun `users are loaded on init`() {
fakeRepo.usersToReturn = listOf(User(1, "Alice"), User(2, "Bob"))
viewModel.loadUsers()
val result = viewModel.users.value
assertNotNull(result)
assertEquals(2, result?.size)
}
}การทดสอบโครูทีน
ใช้ TestCoroutineDispatcher / StandardTestDispatcher เพื่อควบคุมการทำงานของโครูทีนในการทดสอบ:
class SyncWorkerTest {
@get:Rule
val instantTaskRule = InstantTaskExecutorRule()
private val testDispatcher = StandardTestDispatcher()
@Before
fun setUp() {
Dispatchers.setMain(testDispatcher)
}
@After
fun tearDown() {
Dispatchers.resetMain()
}
@Test
fun `sync completes successfully`() = runTest {
val repo = FakeRepository()
val worker = SyncUseCase(repo, testDispatcher)
val result = worker.run()
assertTrue(result.isSuccess)
}
}Fake เทียบกับ Mock
กลยุทธ์สองแบบสำหรับแทนที่การพึ่งพาจริงในการทดสอบ:
- Fake — การนำไปใช้งานที่ทำงานได้จริงและออกแบบมาเพื่อการทดสอบ (เช่น รายการในหน่วยความจำแทนฐานข้อมูลจริง) เขียนง่าย อ่านง่าย และไม่ต้องใช้ไลบรารี
- Mock — ออบเจ็กต์จำลองที่สร้างโดยอัตโนมัติ บันทึกการเรียกใช้ และให้คุณตรวจสอบการโต้ตอบได้ (Mockito, MockK) มีความสามารถมากกว่า แต่ถ้าใช้มากเกินไปอาจเปราะบาง
ควรใช้ Fake ในกรณีง่าย ๆ และใช้ Mock เมื่อต้องตรวจสอบการเรียกเมธอด
การเขียน Fake
Fake ใช้อินเทอร์เฟซเดียวกับคลาสจริง แต่ใช้พื้นที่จัดเก็บในหน่วยความจำ:
interface UserDao {
fun getAll(): List<User>
fun insert(user: User)
}
class FakeUserDao : UserDao {
private val storage = mutableListOf<User>()
override fun getAll(): List<User> = storage.toList()
override fun insert(user: User) { storage.add(user) }
fun clear() { storage.clear() }
}รูปแบบการตั้งชื่อการทดสอบ
ชื่อการทดสอบที่ดีควรอธิบายสิ่งที่กำลังทดสอบและผลลัพธ์ที่คาดหวัง ใช้ชื่อฟังก์ชันในเครื่องหมาย backtick ของ Kotlin เพื่อให้คำอธิบายอ่านง่าย:
`getUsers returns empty list when no users exist``login throws exception when password is blank``add returns correct sum for negative numbers`
รูปแบบ: `subject does X when Y`
ตรวจสอบความเข้าใจ
@Before มีจุดประสงค์ใดในคลาสการทดสอบ JUnit
ทบทวน: การทดสอบหน่วยด้วย JUnit
แอปที่เชื่อถือได้คือแอปที่ผ่านการทดสอบ:
- การทดสอบหน่วยอยู่ใน
src/test/และทำงานบน JVM — รวดเร็ว - ใส่คำอธิบายประกอบด้วย
@Testและใช้assertEquals,assertTrue,assertThrows @Before/@Afterสำหรับการเตรียมและล้างสถานะInstantTaskExecutorRuleสำหรับทดสอบ LiveData แบบพร้อมกันrunTest+StandardTestDispatcherสำหรับการทดสอบโครูทีน- ควรใช้ Fake แทน Mock สำหรับการแทนที่แบบง่าย
ถัดไป: การจำลองด้วย Mockito เพื่อตรวจสอบการโต้ตอบ
เรียนรู้ Kotlin ด้วย AI tutor — ฟรี
เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป
- คอร์ส
- 36
- บทเรียน
- 152
คำถามที่พบบ่อย
บทเรียน “การทดสอบหน่วยด้วย JUnit” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การทดสอบหน่วยด้วย JUnit” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Android Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Android Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การทดสอบหน่วยด้วย JUnit”
เขียนการทดสอบหน่วยที่รวดเร็วและเชื่อถือได้ด้วย JUnit 4 ใช้ @Test, @Before, @After และการตรวจสอบ ทดสอบ LiveData ด้วย InstantTaskExecutorRule และทดสอบโครูทีนด้วย runTest คุณปฏิบัติ Android Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Android Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Android Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน
บทเรียน “การทดสอบหน่วยด้วย JUnit” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Android Academy นี้ได้ไหม
ได้ บทเรียน Android Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การทดสอบหน่วยด้วย JUnit
- การจำลองด้วย Mockito
- การทดสอบส่วนติดต่อผู้ใช้ด้วย Espresso
- การดีบักและการวิเคราะห์ประสิทธิภาพ