Android Academy · บทเรียน

การทดสอบหน่วยด้วย JUnit

เขียนการทดสอบหน่วยที่รวดเร็วและเชื่อถือได้ด้วย JUnit 4 ใช้ @Test, @Before, @After และการตรวจสอบ ทดสอบ LiveData ด้วย InstantTaskExecutorRule และทดสอบโครูทีนด้วย runTest

บทเรียน 1 จาก 413 ขั้นตอน

การทดสอบหน่วยด้วย 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การทดสอบหน่วยด้วย JUnit
  2. การจำลองด้วย Mockito
  3. การทดสอบส่วนติดต่อผู้ใช้ด้วย Espresso
  4. การดีบักและการวิเคราะห์ประสิทธิภาพ
← กลับไปที่ Android Academy