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

ทดสอบและพัฒนา DSL โดยไม่ทำลายผู้ใช้

ออกแบบ API ของ DSL ให้มีเสถียรภาพและทดสอบด้วยบล็อก assertion ที่อ่านเข้าใจง่าย

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

เหตุใดการทดสอบ DSL จึงแตกต่าง

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

การทดสอบ output ของ DSL

การทดสอบที่ง่ายที่สุดคือ สร้างออบเจ็กต์โดยใช้ DSL แล้วตรวจสอบ output ที่แสดงผลหรือสถานะภายในของตัวสร้าง

@Test
fun `div contains a paragraph`() {
    val result = html {
        body {
            div { p("Hi") }
        }
    }
    assertTrue(result.render().contains("<p>"))
}

การทดสอบสถานะของตัวสร้าง

แทนที่จะทดสอบข้อความที่แสดงผล ให้ทดสอบกราฟออบเจ็กต์ของตัวสร้างโดยตรง วิธีนี้ทนทานต่อการเปลี่ยนแปลงรูปแบบมากกว่า:

@Test
fun `server config has correct port`() {
    val cfg = server {
        host = "example.com"
        port = 9090
    }
    assertEquals(9090, cfg.port)
    assertEquals("example.com", cfg.host)
}

การทดสอบโครงสร้างซ้อนกัน

เดินดูต้นไม้ออบเจ็กต์เพื่อตรวจสอบความสัมพันธ์ของการซ้อนกัน:

@Test
fun `body contains one div`() {
    val page = html { body { div { } } }
    assertEquals(1, page.children
        .filterIsInstance<Body>().first()
        .children.filterIsInstance<Div>().size
    )
}

การทดสอบข้อผิดพลาดขณะคอมไพล์

คุณไม่สามารถทดสอบข้อผิดพลาดขณะคอมไพล์ด้วยการทดสอบหน่วยได้โดยตรง แต่สามารถเพิ่มความคิดเห็นอย่าง // This should NOT compile พร้อมใส่โค้ดที่ทำให้เกิดข้อผิดพลาดไว้ในความคิดเห็นได้ บางโครงการใช้ไลบรารี Kotlin Compile Testing เพื่อยืนยันว่าโค้ดบางส่วนคอมไพล์ไม่ได้

การพัฒนา DSL อย่างปลอดภัย: การเปลี่ยนแปลงแบบเพิ่ม

การเพิ่มพารามิเตอร์ทางเลือกใหม่ที่มีค่าเริ่มต้น หรือฟังก์ชันตัวสร้างใหม่ เป็นการเปลี่ยนแปลงที่เข้ากันได้กับเวอร์ชันก่อนหน้า จุดเรียกใช้เดิมยังคงคอมไพล์ได้โดยไม่ต้องเปลี่ยนแปลง

// Before
fun server(block: ServerConfig.() -> Unit): ServerConfig
// After — additive: new optional feature
fun server(enableMetrics: Boolean = false, block: ServerConfig.() -> Unit): ServerConfig

การเปลี่ยนแปลงที่ทำให้เข้ากันไม่ได้: การลบหรือการเปลี่ยนชื่อ

การลบหรือเปลี่ยนชื่อฟังก์ชัน DSL ทำให้จุดเรียกใช้เสียหาย หากจำเป็นต้องเปลี่ยนชื่อ ให้จัดเตรียมนามแฝงที่เลิกใช้แล้ว และลบออกในเวอร์ชันหลักถัดไป:

@Deprecated("Use database{} instead", ReplaceWith("database(block)"))
fun db(block: DbConfig.() -> Unit) = database(block)

การจัดการเวอร์ชันของ DSL

สำหรับ DSL ของไลบรารี ให้ปฏิบัติตามการกำหนดเวอร์ชันตามความหมาย การเปลี่ยนแปลง DSL ที่ทำให้เข้ากันไม่ได้ เช่น การลบฟังก์ชันหรือเปลี่ยนชนิดของตัวรับ ควรเพิ่มหมายเลขเวอร์ชันหลัก โปรดบันทึกการเปลี่ยนแปลงเหล่านี้ไว้ในบันทึกการเปลี่ยนแปลง

การใช้ @RequiresOptIn สำหรับฟีเจอร์ DSL รุ่นทดลอง

ทำเครื่องหมายส่วนขยาย DSL ที่ยังไม่เสถียรด้วย @RequiresOptIn ผู้ใช้ต้องเลือกเข้าร่วมอย่างชัดเจน จึงป้องกันการพึ่งพาฟีเจอร์ที่อาจเปลี่ยนแปลงโดยไม่ตั้งใจได้:

@RequiresOptIn(message = "This DSL feature is experimental and may change")
annotation class ExperimentalDsl

@ExperimentalDsl
fun ServerConfig.enableDebug() { /*...*/ }

การมอบหมายคุณสมบัติใน DSL

DSL สามารถใช้การมอบหมายคุณสมบัติเพื่อบังคับให้ระบุช่องข้อมูลที่จำเป็น และแสดงข้อความข้อผิดพลาดที่ชัดเจนเมื่อไม่มีค่าที่จำเป็น:

class Required<T> {
    private var value: T? = null
    operator fun getValue(t: Any?, p: KProperty<*>): T = value ?: error("${p.name} is required")
    operator fun setValue(t: Any?, p: KProperty<*>, v: T) { value = v }
}

การทดสอบสัญญาข้ามเวอร์ชัน

เก็บข้อมูลโค้ดการใช้งาน DSL “มาตรฐาน” ชุดหนึ่งไว้เป็นการทดสอบ หากการปรับโครงสร้างโค้ดทำให้ข้อมูลเหล่านี้เสียหาย ชุดการทดสอบจะตรวจพบก่อนที่ผู้ใช้จะพบ นอกจากนี้ยังทำหน้าที่เป็นเอกสารที่มีชีวิตด้วย

ตรวจสอบอย่างรวดเร็ว

การเปลี่ยนแปลง DSL ประเภทใดปลอดภัยที่สุดสำหรับความเข้ากันได้กับเวอร์ชันก่อนหน้า

สรุปทบทวน: การทดสอบและการพัฒนา DSL

ประเด็นสำคัญ:

  • ทดสอบ output ของ DSL และสถานะออบเจ็กต์ของตัวสร้างในการทดสอบหน่วย
  • การเปลี่ยนแปลงแบบเพิ่ม เช่น ฟังก์ชันหรือพารามิเตอร์ทางเลือกใหม่ เป็นการเปลี่ยนแปลงที่ปลอดภัย
  • ใช้ @Deprecated(ReplaceWith=...) เพื่อเปลี่ยนชื่อโดยไม่ทำให้ผู้ใช้เดิมเสียหาย
  • ใช้ @RequiresOptIn สำหรับฟีเจอร์ DSL รุ่นทดลอง
  • เก็บการทดสอบการใช้งานมาตรฐานไว้เพื่อตรวจจับการถดถอยข้ามเวอร์ชัน

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

บทเรียน “ทดสอบและพัฒนา DSL โดยไม่ทำลายผู้ใช้” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “ทดสอบและพัฒนา DSL โดยไม่ทำลายผู้ใช้”

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

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

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

บทเรียน “ทดสอบและพัฒนา DSL โดยไม่ทำลายผู้ใช้” ใช้เวลานานแค่ไหน

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

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

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

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

  1. Lambda พร้อมตัวรับ: รากฐานของ DSL
  2. @DslMarker: ป้องกันการรั่วไหลของตัวรับ
  3. สร้าง DSL สำหรับ HTML/การกำหนดค่าที่ปลอดภัยด้านชนิด
  4. ทดสอบและพัฒนา DSL โดยไม่ทำลายผู้ใช้
← กลับไปที่ Kotlin Academy