บทความที่ 3 : การบูรณาการของ Jackson เพื่อการทำพาร์ส YAML ด้วย TDD ในปลั๊กอิน Gradle
เผยแพร่เมื่อ 25 September 2025
บทนำ
ในการพัฒนาโปรเจ็กต์ปลั๊กอิน Gradle การจัดการการกำหนดค่าที่ซับซ้อนเป็นงานที่ทำบ่อย แทนที่จะทำให้ DSL เต็มไปด้วยหลายร้อยคุณสมบัติ มักจะดีและบำรุงรักษาง่ายขึ้นเมื่อกำหนดการตั้งค่าไว้ในไฟล์ภายนอก เช่น YAML บทความนี้แนะนำวิธีการผสานไลบรารีที่ทรงพลัง Jackson เพื่อแปลงไฟล์ YAML เป็นวัตถุ Kotlin โดยใช้แนวทาง TDD อย่างเข้มงวดเพื่อให้แน่ใจว่าปลั๊กอินของเรามีความแข็งแกร่ง`site-baker`.
บริบท : ปลั๊กอินของเรา `site-baker
ปลั๊กอินของเรา`site-baker`ถูกออกแบบมาเพื่อให้ทำการสร้างและเผยแพร่เว็บไซต์แบบคงที่ได้อย่างอัตโนมัติ. จำเป็นต้องอ่านไฟล์กำหนดค่า YAML (managed-jbake-context.yml) เพื่อรับข้อมูลต่าง ๆ เช่น เส้นทางของแหล่งที่มา จุดหมายในการปรับใช้ และรหัส Git
การกำหนดค่า YAML ที่เราต้องการทำการวิเคราะห์มีลักษณะดังนี้:
bake:
srcPath: "./site/jbake"
destDirPath: "bake"
cname: "cheroliv.com"
pushPage:
from: "bake"
to: "cvs"
repo:
name: "trainings"
repository: "https://github.com/pages-content/pages-content.github.io.git"
credentials:
username: "USERNAME"
password: "SECRET_TOKEN"
branch: "main"
message: "cheroliv.com"
# ... autres configurations (pushMaquette, supabase, etc.)
การสร้างแบบจำลองการตั้งค่าใน Kotlin
ก่อนที่จะทำการพาร์ส เราต้องกำหนดโครงสร้างข้อมูลของเราในภาษา Kotlin ไว้ก่อน และแจ็คสันจะใช้คลาสเหล่านี้เพื่อแมปเนื้อหาของไฟล์ YAML ได้โดยอัตโนมัติ
// plugin/src/main/kotlin/com/cheroliv/site/baker/data/SiteConfiguration.kt
package com.cheroliv.site.baker.data
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
import com.fasterxml.jackson.module.kotlin.readValue
import com.fasterxml.jackson.module.kotlin.registerKotlinModule
fun parseSiteConfiguration(yaml: String): SiteConfiguration {
val mapper = ObjectMapper(YAMLFactory()).registerKotlinModule()
return mapper.readValue(yaml)
}
data class GitPushConfiguration(
val from: String = "",
val to: String = "",
val repo: RepositoryConfiguration = RepositoryConfiguration(),
val branch: String = "",
val message: String = "",
)
data class RepositoryConfiguration(
val name: String = "",
val repository: String = "",
val credentials: RepositoryCredentials = RepositoryCredentials(),
) {
companion object {
const val ORIGIN = "origin"
const val CNAME = "CNAME"
const val REMOTE = "remote"
}
}
data class RepositoryCredentials(val username: String = "", val password: String = "")
data class SiteConfiguration(
val bake: BakeConfiguration = BakeConfiguration(),
val pushPage: GitPushConfiguration = GitPushConfiguration(),
val pushMaquette: GitPushConfiguration = GitPushConfiguration(),
val pushSource: GitPushConfiguration? = null,
val pushTemplate: GitPushConfiguration? = null,
val supabase: SupabaseContactFormConfig? = null
)
data class BakeConfiguration(
val srcPath: String = "",
val destDirPath: String = "",
val cname: String? = null,
)
// ... (autres data classes pour Supabase, si nécessaire)
ฟังก์ชัน`parseSiteConfiguration`เป็นจุดเริ่มต้นสำหรับการทำดีซีเรียลไลซ์ของเรา เธอใช้งาน`ObjectMapper`ของ Jackson, ที่กำหนดค่าโดยใช้`YAMLFactory`สำหรับรูปแบบ YAML และ`registerKotlinModule()`เพื่อการสนับสนุนคุณลักษณะเฉพาะของ Kotlin (เช่น ค่าเริ่มต้นของคุณสมบัติ).
3. การผสานรวม Jackson ใน `build.gradle.kts
เพื่อใช้งาน Jackson เราต้องเพิ่มการพึ่งพาที่จำเป็นลงใน`build.gradle.kts`ของโมดูลเรา`plugin`:
// plugin/build.gradle.kts
dependencies {
// Jackson for YAML parsing
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.18.3")
implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.18.3")
// ... autres dépendances
}
เราใช้`jackson-module-kotlin`เพื่อการสนับสนุน Kotlin และ`jackson-dataformat-yaml`เพื่อการจัดการรูปแบบ YAML
4. วิธีการ TDD : ทดสอบการวิเคราะห์ YAML
ตอนนี้เรามาใช้ TDD เพื่อตรวจสอบตรรกะการวิเคราะห์ของเรากันเถอะ
4.1. ทดสอบหน่วย : แมป YAML เป็นออบเจกต์ Kotlin
เราเริ่มต้นด้วยการทดสอบหน่วยใน`SiteBakerPluginTest.kt`เพื่อตรวจสอบว่าฟังก์ชั่น`parseSiteConfiguration`สามารถแปลงสตริง YAML เป็นวัตถุได้อย่างถูกต้อง`SiteConfiguration`.
// plugin/src/test/kotlin/com/cheroliv/site/baker/SiteBakerPluginTest.kt
@Test
fun `can map configuration text to SiteConfiguration object`() {
val yamlString = "../../managed-jbake-context.yml"
.run(::File)
.readText()
.trimIndent()
val config: SiteConfiguration = parseSiteConfiguration(yamlString)
assertEquals("cheroliv.com", config.bake.cname)
assertEquals("main", config.pushPage.branch)
assertEquals("https://github.com/pages-content/pages-content.github.io.git", config.pushPage.repo.repository)
}
การทดสอบนี้อ่านเนื้อหาของไฟล์`managed-jbake-context.yml`(ซึ่งจำเป็นต้องมีเพื่อให้การทดสอบเป็นที่ใช้ได้) และทำการยืนยันกับวัตถุนี้`SiteConfiguration`เป็นผลลัพธ์ที่ได้. ตรวจสอบว่าค่าคีย์ใน YAML นั้นถูกแมปอย่างถูกต้อง。
4.2. ทดสอบการทำงาน : ตรวจสอบการอ่านไฟล์การตั้งค่า
เพื่อให้แน่ใจว่าปลั๊กอินสามารถอ่านไฟล์การกำหนดค่าโดยใช้ DSL ของมันและการวิเคราะห์ทำงานในสภาพแวดล้อม Gradle จริง เราจึงเพิ่มการทดสอบฟังก์ชันลงใน`SiteBakerPluginFunctionalTest.kt`.
การทดสอบนี้มีความสำคัญเนื่องจากมันจำลองการดำเนินการของปลั๊กอินในโครงการจริง มันต้องเป็นปิดสนิท, กล่าวคือ เขาต้องสร้างไฟล์นี้ด้วยตัวเอง`managed-jbake-context.yml`ด้วยเนื้อหาที่ควบคุมไว้ เพื่อรับประกันความสามารถในการทำซ้ำและการแยกส่วนของการทดสอบ
// plugin/src/functionalTest/kotlin/com/cheroliv/site/baker/SiteBakerPluginFunctionalTest.kt
@Test
fun `config file contains good data`(){
val configContent = configFile.readText(UTF_8)
// Vérifications comme dans vos commentaires
assertTrue(configContent.contains("bake"))
assertTrue(configContent.contains("pushPage"))
assertTrue(configContent.contains("repository"))
}
การทดสอบเชิงฟังก์ชันนี้ตรวจสอบว่า ไฟล์การกำหนดค่าที่ถูกคัดลอกไปยังโฟลเดอร์ชั่วคราวของการทดสอบ มีข้อมูลตามที่คาดหวัง. แม้ว่าการทดสอบนี้จะไม่ได้วิเคราะห์ YAML เป็นวัตถุ Kotlin โดยตรง แต่จะตรวจสอบความมีอยู่ของไฟล์และเนื้อหา ซึ่งเป็นขั้นตอนเบื้องต้นที่จำเป็นต่อการทำการวิเคราะห์โดยปลั๊กอิน
5. การแสดงผลของการไหลของการวิเคราะห์
แผนภาพต่อไปนี้แสดงให้เห็นการไหลของข้อมูลและปฏิสัมพันธ์ระหว่างการวิเคราะห์คอนฟิกูเรชัน YAML:
@startuml
actor "ผู้ใช้ Gradle" as User
participant "build.gradle.kts" as BuildScript
participant "SiteBakerPlugin" as Plugin
participant "SiteExtension" as Extension
participant "managed-jbake-context.yml" as ConfigFile
participant "parseSiteConfiguration()" as Parser
participant "SiteConfiguration (วัตถุ Kotlin)" as KotlinObject
User -> BuildScript : ใช้ปลั๊กอินและตั้งค่า DSL
BuildScript -> Plugin : apply()
Plugin -> Extension : สร้างและบันทึกส่วนขยาย 'site'
User -> BuildScript : ไซต์ { configPath = "..." }
BuildScript -> Extension : กำหนด configPath
Plugin -> ConfigFile : อ่านไฟล์ (ผ่าน configPath)
ConfigFile --> Plugin : เนื้อหา YAML
Plugin -> Parser : เรียก parseSiteConfiguration(yamlString)
Parser -> KotlinObject : แมพ YAML เป็นออบเจกต์ SiteConfiguration
KotlinObject --> Plugin : ส่งกลับวัตถุที่กำหนดค่าแล้ว
@enduml
สรุป
ด้วยการปฏิบัติตามแนวทาง TDD เราได้บูรณาการไลบรารี Jackson เพื่อทำการพาร์สไฟล์การกำหนดค่า YAML เป็นอ็อบเจ็กต์ Kotlin ในปลั๊กอิน Gradle ของเราอย่างสำเร็จ. วิธีนี้ทำให้เราสามารถ:
-
ทำการสร้างแบบจำลองอย่างชัดเจนการตั้งค่าของเราด้วยคลาส data ของ Kotlin
-
ตรวจสอบตรรกะของการพาร์ซด้วยการทดสอบหน่วยที่เฉพาะเจาะจง.
-
รับประกันการบูรณาการในสภาพแวดล้อม Gradle จริงๆ ผ่านการทดสอบเชิงฟังก์ชันที่เป็นเฮอร์เมติก
ฐานที่มั่นคงนี้ทำให้เรามีความมั่นใจอย่างยิ่งในการขยายปลั๊กอินของเราด้วยฟีเจอร์ต่างๆ ที่พึ่งพาการตั้งค่านี้ พร้อมทั้งรับประกันความสามารถในการบำรุงรักษาและความแข็งแกร่งของโค้ด การวิเคราะห์ YAML ได้กลายเป็นฟีเจอร์ที่เชื่อถือได้และได้รับการทดสอบแล้วของปลั๊กอินของเรา`site-baker`.