ในบทความนี้ เราจะสำรวจวิธีการตั้งค่าพื้นฐานการพัฒนาที่แข็งแรงสำหรับปลั๊กอิน 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. การทดสอบการบูรณาการ: สร้างสภาพแวดล้อมที่ควบคุมได้

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

การทดสอบจึง :

  1. สร้าง`build.gradle.kts`ไฟล์ทดสอบที่ใช้ปลั๊กอินของเราและ DSL ของมัน

  2. สร้างไฟล์กำหนดค่า(managed-jbake-context.yml) ที่ปลั๊กอินควรจะอ่าน. นี่เป็นขั้นตอนที่สำคัญสำหรับความเสถียรของการทดสอบ

  3. ดำเนินการงาน`printSiteConfig`ผ่าน`GradleRunner`.

  4. ตรวจสอบว่าผลลัพธ์ของการสร้างเป็นไปอย่างถูกต้อง

การคัดลอกหรือสร้างไฟล์การกำหนดค่านี้ในแต่ละครั้งที่ทำงาน เราจะมั่นใจว่าการทดสอบสามารถทำซ้ำได้และไม่ขึ้นอยู่กับสถานะภายนอก. ซึ่งทำให้การทดสอบของเราปลอดภัยจากการถดถอยที่อาจเชื่อมโยงกับการอ่านไฟล์

@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

ฐานการทดสอบที่เข้มแข็งนี้คือสินทรัพย์ที่มีค่าที่สุดสำหรับการบำรุงและการพัฒนาเพิ่มเติมของปลั๊กอินในอนาคต

บทความที่เกี่ยวข้อง