0Pricing
Swift Academy · บทเรียน

การทดสอบโมเดลมุมมอง

ทดสอบตรรกะการนำเสนอแบบหน่วยโดยแยกออกจากส่วนอื่น

การทดสอบโมเดลมุมมอง เป็นบทเรียน Swift Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Swift Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Swift Academy มีบทเรียนทั้งหมด 4 บทเรียน

เหตุใดจึงต้องทดสอบ ViewModel

ViewModel เก็บตรรกะการนำเสนอของคุณไว้ จึงเป็นชั้นที่มีคุณค่ามากที่สุดสำหรับการทดสอบหน่วย เนื่องจากไม่มีการพึ่งพา UIKit หรือ SwiftUI คุณจึงสามารถทดสอบได้ โดยแยกเป็นอิสระ อย่างรวดเร็วและได้ผลลัพธ์แน่นอน

ออกแบบมาให้ทดสอบได้

ViewModel ที่สร้างมาอย่างดีจะรับสิ่งที่ต้องพึ่งพาผ่านตัวสร้าง การทำเช่นนี้ทำให้การทดสอบแทนที่สิ่งเหล่านั้นด้วยตัวจำลองได้

final class WeatherViewModel: ObservableObject {
    @Published var temperatureText = ""
    private let service: WeatherService

    init(service: WeatherService) {
        self.service = service
    }
}

การฉีดสิ่งที่ต้องพึ่งพา

ซ่อนสิ่งที่ต้องพึ่งพารูปธรรมไว้เบื้องหลัง โพรโทคอล ViewModel จะพึ่งพานามธรรม ทำให้การทดสอบสามารถฉีด mock ได้

protocol WeatherService {
    func fetchTemperature() async throws -> Double
}

เขียน mock

mock นำโพรโทคอลไปใช้และส่งคืนข้อมูลที่เตรียมไว้ ทำให้คุณควบคุมได้อย่างแม่นยำว่า ViewModel จะเห็นอะไร

final class MockWeatherService: WeatherService {
    var stubbedTemperature: Double = 20
    var didCallFetch = false

    func fetchTemperature() async throws -> Double {
        didCallFetch = true
        return stubbedTemperature
    }
}

การทดสอบหน่วยพื้นฐาน

เมื่อฉีด mock เข้าไปแล้ว คุณจะตรวจสอบได้ว่า ViewModel แปลงข้อมูลได้อย่างถูกต้อง

func testFormatsTemperature() async {
    let mock = MockWeatherService()
    mock.stubbedTemperature = 25
    let vm = WeatherViewModel(service: mock)

    await vm.load()

    XCTAssertEqual(vm.temperatureText, "25 C")
}

ทดสอบการเปลี่ยนสถานะ

ViewModel มักเปิดเผยสถานะในรูปแบบ enum ให้ทดสอบแต่ละแขนงด้วยการป้อนข้อมูลที่ทำให้เกิดสถานะนั้น

func testLoadingThenLoaded() async {
    let vm = FeedViewModel(service: MockFeedService())
    XCTAssertEqual(vm.state, .loading)

    await vm.load()

    XCTAssertEqual(vm.state, .loaded(["A", "B"]))
}

ทดสอบเส้นทางข้อผิดพลาด

ทำให้ mock โยนข้อผิดพลาดเพื่อยืนยันว่า ViewModel จัดการความล้มเหลวได้อย่างเหมาะสมและส่งต่อสถานะข้อผิดพลาด

final class FailingService: WeatherService {
    func fetchTemperature() async throws -> Double {
        throw URLError(.notConnectedToInternet)
    }
}

func testShowsErrorOnFailure() async {
    let vm = WeatherViewModel(service: FailingService())
    await vm.load()
    XCTAssertEqual(vm.state, .error)
}

ตรวจสอบการโต้ตอบ

บางครั้งสิ่งที่คุณสนใจคือสิ่งที่ต้องพึ่งพาถูก เรียกใช้ ไม่ใช่เพียงผลลัพธ์เท่านั้น แฟล็กสำหรับสอดส่องบน mock ช่วยให้คุณตรวจสอบพฤติกรรมได้

func testFetchIsCalled() async {
    let mock = MockWeatherService()
    let vm = WeatherViewModel(service: mock)
    await vm.load()
    XCTAssertTrue(mock.didCallFetch)
}

ทดสอบผลลัพธ์ของ @Published

คุณสามารถสมัครรับค่าจากพร็อพเพอร์ตี @Published ด้วย Combine เพื่อเก็บค่าที่ส่งออกมาและตรวจสอบลำดับของค่า

var received: [String] = []
let cancellable = vm.$temperatureText.sink { received.append($0) }

await vm.load()

XCTAssertEqual(received.last, "25 C")
cancellable.cancel()

ทำให้การทดสอบรวดเร็ว

เนื่องจาก mock ส่งค่ากลับทันทีและไม่มีเครือข่ายจริง การทดสอบ ViewModel จึงทำงานเสร็จในระดับ milliseconds หลีกเลี่ยงตัวจับเวลาจริงและ URLSession — ให้ฉีดตัวจำลองสำหรับนาฬิกาและตัวจัดตารางเวลาด้วย

แนวทางปฏิบัติที่ดี

การทดสอบ ViewModel ที่มีประสิทธิภาพ:

  • ฉีดสิ่งที่ต้องพึ่งพาทั้งหมดผ่านโพรโทคอล
  • ทดสอบพฤติกรรมหนึ่งอย่างต่อหนึ่งเมธอดทดสอบ
  • ครอบคลุมเส้นทางสำเร็จ ว่างเปล่า และข้อผิดพลาด
  • ตรวจสอบผลลัพธ์ที่เผยแพร่ซึ่งมุมมองจะอ่าน

ตรวจสอบความเข้าใจ

ทดสอบความรู้เกี่ยวกับการทดสอบ ViewModel ของคุณ

สรุป

คุณได้เรียนรู้การทดสอบหน่วยของ ViewModel โดยแยกเป็นอิสระ:

  • ฉีดสิ่งที่ต้องพึ่งพาไว้เบื้องหลังโพรโทคอล
  • ใช้ mock เพื่อควบคุมข้อมูลป้อนเข้าและสอดส่องการเรียกใช้
  • ครอบคลุมสถานะสำเร็จ ข้อผิดพลาด และว่างเปล่า
  • ตรวจสอบผลลัพธ์ @Published และการเปลี่ยนสถานะ

ViewModel ที่ทดสอบได้คือผลลัพธ์จากการแยกหน้าที่ของ MVVM

คำถามที่พบบ่อย

บทเรียน “การทดสอบโมเดลมุมมอง” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การทดสอบโมเดลมุมมอง” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Swift Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Swift Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การทดสอบโมเดลมุมมอง”

ทดสอบตรรกะการนำเสนอแบบหน่วยโดยแยกออกจากส่วนอื่น คุณปฏิบัติ Swift Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Swift Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Swift Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “การทดสอบโมเดลมุมมอง” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Swift Academy นี้ได้ไหม

ได้ บทเรียน Swift Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

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

  1. รูปแบบ MVVM
  2. การผูกโมเดลมุมมองเข้ากับมุมมอง
  3. รูปแบบ Coordinator
  4. การทดสอบโมเดลมุมมอง
← กลับไปที่ Swift Academy