Show how you'd use ProjectBuilder to assert that your plugin registered a task, added an extension, and created a configuration.
answer
- build → apply → assert
- tasks.findByName / extensions.findByType / configurations.findByName
- findByName null vs getByName throws
- register() realized on query
- Property.get() reads defaults
basics
~10 sBuild a Project, apply the plugin, then assert: project.tasks.findByName("x"), project.extensions.findByName("y"), and project.configurations.findByName("z") are non-null. Each check confirms a piece of configuration-phase wiring.
solid answer
~30 sAfter `val project = ProjectBuilder.builder().build()` and `project.plugins.apply(MyPlugin::class.java)`, you assert against the project's containers. Use `findByName(...)` (returns null when absent) rather than `getByName(...)` (throws) when you want clean assertions. For a **task**: `assertNotNull(project.tasks.findByName("deploy"))`, and you can cast/check its type or properties. For an **extension**: `val ext = project.extensions.findByType(MyExtension::class.java); assertNotNull(ext); assertEquals("default", ext!!.value.get())` — extensions registered via `extensions.create` expose their `Property` defaults at configuration time. For a **configuration**: `assertNotNull(project.configurations.findByName("myTool"))`, and you can check `isCanBeResolved`/`isCanBeConsumed`. Because the lazy task/`Property` APIs are realized at configuration time, these assertions verify exactly the wiring your plugin's `apply()` performed, without running the build.
code
kotlin · 18 lines@Test
fun `plugin wires task, extension, and configuration`() {
val project = ProjectBuilder.builder().build()
project.plugins.apply(MyPlugin::class.java)
// task
assertNotNull(project.tasks.findByName("deploy"))
// extension + its default
val ext = project.extensions.findByType(GreetingExtension::class.java)
assertNotNull(ext)
assertEquals("Hello", ext!!.message.get())
// configuration role
val conf = project.configurations.findByName("myTool")
assertNotNull(conf)
assertTrue(conf!!.isCanBeResolved)
}go deeper
Demonstrate the build→apply→assert pattern with findByName for a task and an extension.
Show all three container types, prefer findByName, and read Property defaults via get(); know register realizes on query.
Discuss asserting configuration roles (resolvable/consumable) and configured Property values, and why these stay in the configuration phase.
Define a reusable test helper/convention for plugin wiring assertions so teams write consistent, fast coverage across many plugins.
## The pattern: build → apply → assert Every ProjectBuilder wiring test follows three steps. ```kotlin val project = ProjectBuilder.builder().build() // 1. build project.plugins.apply(MyPlugin::class.java) // 2. apply // 3. assert against project's containers ``` ## Asserting a task was registered `project.tasks` is a `TaskContainer`. Prefer `findByName` (nullable, no throw) for assertions: ```kotlin assertNotNull(project.tasks.findByName("deploy")) val task = project.tasks.findByName("deploy") as MyDeployTask assertEquals("prod", task.environment.get()) ``` Note: if your plugin uses the lazy `tasks.register("deploy")`, the task provider isn't *realized* until something queries it. Calling `findByName` (or `getByName`/`named(...).get()`) forces realization, so the registration action runs and you can inspect the configured object. ## Asserting an extension was added Extensions added via `project.extensions.create("greeting", GreetingExtension::class.java)` are available immediately: ```kotlin val ext = project.extensions.findByType(GreetingExtension::class.java) assertNotNull(ext) assertEquals("Hello", ext!!.message.get()) // Property default ``` `findByType` resolves by class; `findByName` resolves by the registered name. Both are valid. ## Asserting a configuration was created `project.configurations` is the `ConfigurationContainer`. A plugin commonly creates and shapes a configuration's role: ```kotlin val conf = project.configurations.findByName("myTool") assertNotNull(conf) assertTrue(conf!!.isCanBeResolved) assertFalse(conf.isCanBeConsumed) ``` In modern Gradle you'd typically create roles via `configurations.resolvable("myTool")` or `configurations.consumable("myToolElements")`; ProjectBuilder lets you assert the resulting `isCanBeResolved`/`isCanBeConsumed` flags. ## findByName vs getByName in tests - `findByName("x")` → returns `null` if missing. Best for `assertNotNull` style — the failure message is your assertion, not an exception. - `getByName("x")` → throws `UnknownDomainObjectException` if missing. Fine, but the test fails with a less intentional message. ## Why this is reliable All three checks observe **configuration-phase** state — exactly the work your `apply()` did. No execution phase is needed, so the tests stay fast and deterministic.
- Why prefer findByName over getByName in a ProjectBuilder assertion?findByName returns null when the object is missing, so `assertNotNull` produces a clear assertion failure. getByName throws UnknownDomainObjectException, which surfaces as a less intentional test error.
- If your plugin registers a task lazily with tasks.register, does it exist for the test to find?Yes — registration creates a provider, and querying it (findByName/named().get()) realizes the task, running its configuration action so you can inspect it. The registration itself is enough; you just have to touch it.
- How do you assert an extension's default value was set correctly?Resolve the extension via findByType, then read its Property with .get(), e.g. ext.message.get(), since extension defaults are applied during apply() at configuration time.
saying these in an interview costs you the question
- Using getByName everywhere and getting confusing exception-based failures.
- Trying to read a task's runtime output (which requires execution) instead of its configured properties.
- Asserting task ordering/dependencies as if they executed — only the wiring is present, not execution results.