Članak 2: Razvoj Gradle plugin-a sa TDD pristupom
Објављено 24 September 2025
U ovom članku bićemo istraživali kako postaviti čvrsto temelj za razvoj Gradle plugina koristeći pristup Test-Driven Development (TDD). Ova metoda nam osigurava da je naš kod robustan, Drživ i tačno odgovara zahtevima od samog početka.
1. Иницијализација пројекта
Gradle olakšava kreiranje novog plugina zahvaljujući naredbi`gradle init`. Izborom da kreiramo "Gradle Plugin" uz Kotlin, dobijamo spremnu strukturu projekta koja uključuje dva ključna tipa testova :
-
Jedinični testovi :položeni u`src/test`, oni omogućavaju validaciju izolovanih komponenti naše dodatka, kao što je interna logika zadatka ili konfiguracija dodatka. Oni su brzi i ne zahtevaju punu izvršavanje Gradle.
-
Funkcionalni testovi :Smješteni u`src/functionalTest`, oni koriste`GradleRunner`Za izvršavanje kompletne Gradle gradnje u privremenom testnom projektu. Ovo nam omogućava da proverimo stvarno ponašanje plugina u kontrolisanom okruženju.
2. Nas prvi TDD ciklus: unesi zadatak
Naša prva zahteva je jednostavna: plugin mora da zabilježi nazvan zadatak`printSiteConfig`.
2.1. Први тест (Тест који није успео)
U skladu sa TDD-om, prvo pišemo test koji proverava da li postoji ovaj zadatak. U`SiteBakerPluginTest.kt`(naš fajl za jedinični test), dodajemo :
@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"))
}
Ovaj test ne uspeva, jer smo još nijedan kod napisali u našem pluginu.
2.2. Kod nakon (Uspostavi test)
Sada, pišemo minimalno potrebni kod u`SiteBakerPlugin.kt`da bi test prošao :
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
}
}
}
Ponovo pokrećemo testove, i oni prolaze. Naša prva funkcionalnost je validovana.
3. Drugi ciklus TDD: Dodati DSL ekstenziju
Sledeći zahtev je omogućiti korisnicima da konfigurisu naš plugin putem DSL bloka u njihovom`build.gradle.kts`. Želimo blok`site { … }`где може да се наведе путања конфигурације.
3.1. Тест први
Dodajemo test da proverimo da li je ekstenzija`site`Je dobro evidentirano i možemo joj dodeliti vrednost.
@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`ni evidencija ekstenzije ne postoji
3.2. Sledeći kod
Kreiramo klasu`SiteBakerExtension.kt`i ažuriramo`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
}
}
}
}
Testovi ponovo prolaze.
4. Funkcionalni test: Validacija integracije
Sada kada su jedinice testirane, moramo se uveriti da sve radi zajedno u stvarnoj gradnji. To je uloga funkcionalnog testa u`SiteBakerPluginFunctionalTest.kt`.
4.1. Test integracije: Kreirati kontrolisano okruženje
Ovaj test će simulirati pravi projekat koji koristi naš plugin. Da bi bio pouzdan, mora bitihermetski, to jest da ne smije zavisiti od postojećih datoteka na sistemu. On mora sam stvoriti sve neophodne uslove za njegovo izvršenje.
Test će dakle :
-
Napraviti jedan`build.gradle.kts`test koji koristi naš plugin i njegov DSL.
-
Kreirajte datoteku konfiguracije(
managed-jbake-context.yml) što plugin treba da pročita. Ovo je ključni korak za robustnost testa. -
Izvršiti zadatak`printSiteConfig`преку`GradleRunner`.
-
Proveri da li je izlaz izgradnje ispravan.
Kopirandom ili stvaranjem ove datoteke konfiguracije pri svakom pokretanju, osiguravamo da je testповторљивi ne zavisi od vanjskog stanja. Ovo zaštičava naše testove od regresija koje bi mogle biti povezane sa čitanjem fajla.
@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"))
}
Ovaj test će neudati dok je zadatak`printSiteConfig`Neće zapravo koristiti vrednost ekstenzije.
4.2. Završiti logiku
Ažuriramo zadatak u`SiteBakerPlugin.kt`da bi prikazala konfigurisanu vrednost:
project.tasks.register("printSiteConfig") { task ->
task.doLast {
println("Site config path: ${extension.configPath.get()}")
}
}
Svi testovi, jedinični i funkcionalni, sada prolaze.
Zaključak
Sledeći pristup TDD, izgradili smo plugin inkrementalno i bezbedno. Svaka mala funkcionalnost se odmah validira testem, od brzi unitarni testovi do funkcionalnih testova koji validiraju kompletnu integraciju.
Pažljivo čineći naše teste funkcionalnimhermetски— naročito programski kreiranjem potrebnih konfiguraционных fajlova — gradimo ekstremno jaku mrežu bezbednosti. Ova riguroznost nam efikasno štiti od regresija i nam daje veliko poverenje da dodajemo složenije funkcionalnosti kasnije, kao što je parsiranje YAML konfiguraционог fajla.
Ova čvrsta baza testova je najvažnija vrednost za održavanje i budući razvoj plugin-a.