ข้อที่ 2 : พัฒนาปลั๊กอิน Gradle ด้วยวิธีการ TDD
เผยแพร่เมื่อ 24 September 2025
ในบทความนี้ เราจะสำรวจวิธีการตั้งค่าพื้นฐานการพัฒนาที่แข็งแรงสำหรับปลั๊กอิน Gradle โดยใช้แนวทางการพัฒนาที่ขับเคลื่อนด้วยการทดสอบ (TDD - Test-Driven Development) วิธีนี้ทำให้มั่นใจได้ว่าโค้ดของเราจะมีความแข็งแรง สามารถบำรุงรักษาได้ และตรงตามความต้องการอย่างแม่นยำตั้งแต่ต้น
การเริ่มต้นโครงการ
Gradle ทำให้การสร้างปลั๊กอินใหม่เป็นเรื่องง่ายขึ้นอย่างมากด้วยคำสั่ง`gradle init`. โดยการเลือกที่จะสร้าง "Gradle Plugin" ด้วย Kotlin เราจะได้โครงสร้างโปรเจ็กต์ที่พร้อมใช้งาน ซึ่งรวมถึงการทดสอบที่สำคัญสองประเภท:
-
การทดสอบหน่วย :ตั้งอยู่ใน`src/test`, พวกเขาสามารถใช้ตรวจสอบคอมโพเนนต์ที่แยกออกของปลั๊กอินของเราได้ เช่น ตรรกะภายในของงานหรือการตั้งค่าของส่วนขยาย พวกเขาทำได้รวดเร็วและไม่จำเป็นต้องทำการรัน Gradle เต็มรูปแบบ
-
การทดสอบฟังก์ชัน :ตั้งอยู่ใน`src/functionalTest`, พวกเขาใช้`GradleRunner`เพื่อทำการสร้าง Gradle เต็มรูปแบบในโครงการทดลองชั่วคราวของเรา นี่จะช่วยให้เราตรวจสอบพฤติกรรมที่เป็นจริงของปลั๊กอินในสภาพแวดล้อมที่มีการควบคุม
2. วัฏจักร TDD ครั้งแรกของเรา: บันทึกงานหนึ่งรายการ
ความต้องการแรกของเราเป็นเรื่องง่าย: ปลั๊กอินต้องบันทึกงานที่ชื่อว่า`printSiteConfig`.
2.1. การทดสอบครั้งแรก (การทดสอบที่ล้มเหลว)
ตามหลักการของ TDD เราเขียนทดสอบก่อนเพื่อตรวจสอบว่ามีงานนี้อยู่จริง. ใน`SiteBakerPluginTest.kt`(ไฟล์ทดสอบหน่วยของเรา), เราเพิ่ม :
@Test
fun `plugin registers task`() {
// Créer un projet de test en mémoire
val project = ProjectBuilder.builder().build()
project.plugins.apply("com.cheroliv.site-baker")
// Vérifier que la tâche a bien été enregistrée
assertNotNull(project.tasks.findByName("printSiteConfig"))
}
การทดสอบนี้ล้มเหลว เพราะเรายังไม่ได้เขียนโค้ดใดๆ ในปลั๊กอินของเรา
2.2. โค้ดต่อไป (ทำให้การทดสอบผ่าน)
ตอนนี้เราเขียนโค้ดขั้นต่ำที่จำเป็นใน`SiteBakerPlugin.kt`เพื่อให้การทดสอบผ่าน :
class SiteBakerPlugin: Plugin<Project> {
override fun apply(project: Project) {
// Enregistrer une tâche simple
project.tasks.register("printSiteConfig") { task ->
// ... la logique de la tâche viendra plus tard
}
}
}
เราทำการรีสตาร์ทการทดสอบและพวกมันผ่านไปแล้ว ฟังก์ชั่นแรกของเราได้รับการตรวจสอบและอนุมัติเรียบร้อยแล้ว.
3. รอบที่สองของ TDD: เพิ่มส่วนขยาย DSL
ความต้องการต่อไปคือการอนุญาตให้ผู้ใช้กำหนดค่าปลั๊กอินของเราผ่านบล็อก DSL ในของพวกเขา`build.gradle.kts`. เราต้องการบล็อก`site { … }`ที่สามารถระบุเส้นทางการกำหนดค่าได้
3.1. การทดสอบครั้งแรก
เพิ่มการทดสอบเพื่อตรวจสอบว่าส่วนขยายนี้`site`ได้บันทึกไว้อย่างดีและเราสามารถกำหนดค่าให้กับมันได้.
@Test
fun `plugin registers extension`() {
val project = ProjectBuilder.builder().build()
project.plugins.apply("com.cheroliv.site-baker")
// Récupérer l'extension et lui affecter une valeur
project.extensions
.findByType(SiteExtension::class.java)!!
.configPath
.set("config.yml")
// Vérifier que la valeur a bien été prise en compte
assertEquals(
"config.yml",
project.extensions.findByType(SiteExtension::class.java)?.configPath?.get()
)
}
การทดสอบนี้ล้มเหลวเพราะไม่ใช่คลาส`SiteExtension`และการลงทะเบียนของส่วนขยายนี้ก็ไม่ได้มีอยู่
3.2. รหัสต่อไป
เรากำลังสร้างคลาส`SiteBakerExtension.kt`และเราอัปเดต`SiteBakerPlugin.kt`:
// SiteBakerExtension.kt
open class SiteExtension @Inject constructor(objects: ObjectFactory) {
val configPath: Property<String> = objects.property(String::class.java)
}
// SiteBakerPlugin.kt
class SiteBakerPlugin: Plugin<Project> {
override fun apply(project: Project) {
// Enregistrer l'extension
val extension = project.extensions.create("site", SiteExtension::class.java)
project.tasks.register("printSiteConfig") { task ->
task.doLast {
// On utilisera l'extension plus tard
}
}
}
}
การทดสอบผ่านอีกครั้ง
4. การทดสอบการทำงาน: ตรวจสอบการบูรณาการ
หลังจากที่หน่วยผ่านการทดสอบแล้ว เราต้องตรวจสอบให้แน่ใจว่าทุกอย่างทำงานร่วมกันในบิลด์จริงๆ. นี่เป็นบทบาทของการทดสอบฟังก์ชันใน`SiteBakerPluginFunctionalTest.kt`.
4.1. การทดสอบการบูรณาการ: สร้างสภาพแวดล้อมที่ควบคุมได้
การทดสอบนี้จะจำลองโครงการจริงโดยใช้ปลั๊กอินของเรา เพื่อให้มันเชื่อถือได้ มันต้องเป็นกันอากาศ, นั่นคือมันจะต้องไม่ขึ้นต่อไฟล์ที่มีอยู่ในระบบ และมันต้องสร้างเงื่อนไขที่จำเป็นทั้งหมดด้วยตัวเองก่อนที่จะทำงาน
การทดสอบจึง :
-
สร้าง`build.gradle.kts`ไฟล์ทดสอบที่ใช้ปลั๊กอินของเราและ DSL ของมัน
-
สร้างไฟล์กำหนดค่า(
managed-jbake-context.yml) ที่ปลั๊กอินควรจะอ่าน. นี่เป็นขั้นตอนที่สำคัญสำหรับความเสถียรของการทดสอบ -
ดำเนินการงาน`printSiteConfig`ผ่าน`GradleRunner`.
-
ตรวจสอบว่าผลลัพธ์ของการสร้างเป็นไปอย่างถูกต้อง
การคัดลอกหรือสร้างไฟล์การกำหนดค่านี้ในแต่ละครั้งที่ทำงาน เราจะมั่นใจว่าการทดสอบสามารถทำซ้ำได้และไม่ขึ้นอยู่กับสถานะภายนอก. ซึ่งทำให้การทดสอบของเราปลอดภัยจากการถดถอยที่อาจเชื่อมโยงกับการอ่านไฟล์
@Test fun `can run task with DSL`() {
// 1. Créer un build.gradle.kts de test
buildFile.writeText("""
plugins { id("com.cheroliv.site-baker") }
site { configPath = "managed-jbake-context.yml" }
""".trimIndent())
// 2. Créer le fichier de configuration pour un test contrôlé
val configFile = File(projectDir, "managed-jbake-context.yml")
configFile.writeText("site: { title: 'Mon Site de Test' }") // Contenu YAML simple
// 3. Exécuter la build
val runner = GradleRunner.create()
runner.withPluginClasspath()
runner.withArguments("printSiteConfig")
runner.withProjectDir(projectDir) // Spécifier le répertoire du projet de test
val result = runner.build()
// 4. Vérifier la sortie
assertTrue(result.output.contains("Site config path: managed-jbake-context.yml"))
}
การทดสอบนี้จะล้มเหลวตราบใดที่งาน`printSiteConfig`มันจะไม่ใช้ค่าของส่วนขยายนี้จริงๆ
4.2. ทำให้ลอจิกเสร็จสมบูรณ์
พวกเรากำลังอัปเดตงานอยู่ภายใน`SiteBakerPlugin.kt`เพื่อให้แสดงค่าที่ตั้งค่าไว้:
project.tasks.register("printSiteConfig") { task ->
task.doLast {
println("Site config path: ${extension.configPath.get()}")
}
}
ตอนนี้การทดสอบทั้งแบบหน่วยและฟังก์ชัน ผ่านทั้งหมดแล้ว
สรุป
โดยการทำตามแนวทาง TDD เราได้สร้างปลั๊กอินอย่างเป็นขั้นตอนและปลอดภัย ฟังก์ชันเล็ก ๆ ทุกฟังก์ชันจะได้รับการตรวจสอบทันทีโดยการทดสอบ ตั้งแต่การทดสอบหน่วยที่รวดเร็วไปจนถึงการทดสอบเชิงฟังก์ชันที่ตรวจสอบการบูรณาการอย่างสมบูรณ์
โดยดูแลให้การทดสอบของเราทำงานได้ปิดผนึก— โดยเฉพาะในการสร้างไฟล์การตั้งค่าที่จำเป็นโดยทางโปรแกรม — เราสร้างตาข่ายความปลอดภัยที่แข็งแกร่งอย่างยิ่ง. ความเข้มงวดนี้ปกป้องเราได้อย่างมีประสิทธิภาพจากการถดถอยและทำให้เรามีความเชื่อมั่นอย่างมากในการเพิ่มฟังก์ชันที่ซับซ้อนยิ่งขึ้นต่อไป เช่น การวิเคราะห์ไฟล์การตั้งค่า YAML
ฐานการทดสอบที่เข้มแข็งนี้คือสินทรัพย์ที่มีค่าที่สุดสำหรับการบำรุงและการพัฒนาเพิ่มเติมของปลั๊กอินในอนาคต