مقاله ۲: توسعه یک پلاگین Gradle با رویکرد TDD
منتشر شده در 24 September 2025
در این مقاله، میخواهیم بررسی کنیم که چگونه میتوانیم یک پایهٔ توسعه محکم برای یک پلاگین Gradle را با استفاده از رویکرد توسعه تست محور (TDD - Test-Driven Development) قرار دهیم. این روش تضمین میکند که کد ما مقاوم، قابل نگهداری و بهطور دقیق با نیازها همخوانی دارد، از ابتدا.
راهاندازی پروژه
Gradle با استفاده از دستور، ایجاد یک پلاگین جدید را بهطور قابلتوجهی آسان میسازد`gradle init`. با انتخاب ایجاد یک 'Gradle Plugin' با Kotlin، ما یک ساختار پروژه آماده استفادهای دریافت میکنیم که شامل دو نوعytest مهم است:
-
تستهای واحدی :واقع در`src/test`, آنها امکان اعتبارسنجی اجزاء جدا شده از پلاگین ما را میدهند، مانند منطق داخلی یک وظیفه یا تنظیمات یک افزونه. آنها سریع هستند و نیازی به اجرای کامل Gradle ندارند.
-
آزمونهای عملکردی :واقع در`src/functionalTest`، آنها استفاده میکنند`GradleRunner`برای اجرای یک ساخت Gradle کامل در یک پروژه آزمایشی موقت. این به ما اجازه میدهد تا رفتار واقعی پلاگین را در محیطی کنترلشده بررسی کنیم.
2. دور اول TDD ما: ثبت یک وظیفه
شرط اول ما ساده است: پلاگین باید یک وظیفه با نام ثبت کند.printSiteConfig.
2.1. آزمایش اول (آزمایشی که شکست میخورد)
طبق TDD، ابتدا یک test بنویسیم که وجود این کار را بررسی میکند. در`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. آزمایش یکپارچهسازی : ایجاد محیط کنترلشده
این تست یک پروژه واقعی استفاده از پلاگین ما را شبیهسازی خواهد کرد. برای اینکه قابل اعتماد باشد، بایدمحرز، به عبارت دیگر، نباید به فایلهای موجود در سیستم وابسته باشد. باید خودانه تمام شرایط لازم برای اجرا را فراهم کند.
آزمون بنابراین :
-
ایجاد یک
(Note: there is a leading space before the translation as in the source)`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.
این پایهٔ تستهای قوی، دارایی ارزشمندترین برای نگهداری و توسعهی آیندهی پلاگین است.