ทดสอบและพัฒนา 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- Lambda พร้อมตัวรับ: รากฐานของ DSL
- @DslMarker: ป้องกันการรั่วไหลของตัวรับ
- สร้าง DSL สำหรับ HTML/การกำหนดค่าที่ปลอดภัยด้านชนิด
- ทดสอบและพัฒนา DSL โดยไม่ทำลายผู้ใช้