# ProjectBuilder Test for VersionCatalog

**URL:** <https://discuss.gradle.org/t/projectbuilder-test-for-versioncatalog/48612>\
**Category:** Help/Discuss\
**Created:** [June 3, 2024, 6:12pm UTC](https://discuss.gradle.org/t/projectbuilder-test-for-versioncatalog/48612 "2024-06-03T18:12:57Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![gsudheer](https://avatars.discourse-cdn.com/v4/letter/g/87869e/32.png) [@gsudheer](https://discuss.gradle.org/u/gsudheer)\
**Post date:** [June 3, 2024, 6:12pm UTC](https://discuss.gradle.org/t/projectbuilder-test-for-versioncatalog/48612/1 "2024-06-03T18:12:57Z")

</div>

Hi,

I’m using version catalog feature in one of my project where I published my catalog to artifactory and in another project (lets say consumer project) I’m importing that catalog.

I have some test cases using ProjectBuilder and some with GradleRunner (Gradle Test Kit). When I run the ProjectBuilder test cases it is giving an error

```gradle
org.gradle.api.UnknownDomainObjectException: Extension of type 'VersionCatalogsExtension' does not exist. Currently registered extension types: [ExtraPropertiesExtension, SpringBootExtension, StandardDependencyManagementExtension, ProjectOperations, AsciidoctorJExtension, OpenApiExtension, OpenApi3Extension, PostmanExtension, BasePluginExtension, DefaultArtifactPublicationSet, SourceSetContainer, ReportingExtension, JavaToolchainService, JavaPluginExtension, TestingExtension, ContractVerifierExtension]
	at org.gradle.internal.extensibility.ExtensionsStorage.getHolderByType(ExtensionsStorage.java:89)
	at org.gradle.internal.extensibility.ExtensionsStorage.getByType(ExtensionsStorage.java:74)
	at org.gradle.internal.extensibility.DefaultConvention.getByType(DefaultConvention.java:172)
	at org.gradle.internal.extensibility.DefaultConvention.getByType(DefaultConvention.java:167)

```

Here is how my custom precompiled plugin is :

**CustomPlugin.kt**

```gradle
class CustomPlugin: Plugin<Project> {

          override fun apply(project: Project) {
                  project.applyDependencies()
           }

           private fun Project.applyDependencies() {
                  val dependencyHandler = project.dependencies
                 val versionCatalog = 
                          project.extensions.getByType(VersionCatalogsExtension::class.java).named("libs")

                 using dependencyHandler.add("implementation" , versionCatalog.findLibrary("springframework-cloud").get().get())
                 ..... // some more dependencies
           }

}

```

**CustomPluginTest.kt**

```gradle
class CustomPluginTest {

    @Test
    fun testDependencies() { 
         val project = ProjectBuilder.builder().build()
    }
}

```

Any help is much appreciated.

Thanks,  
Sudheer.

---

<div class="post-metadata">

**Author:** ![Vampire](https://sea1.discourse-cdn.com/gradle/user_avatar/discuss.gradle.org/vampire/32/9082_2.png) [@Vampire](https://discuss.gradle.org/u/Vampire)\
**Post date:** [June 4, 2024, 11:10am UTC](https://discuss.gradle.org/t/projectbuilder-test-for-versioncatalog/48612/2 "2024-06-04T11:10:24Z")

</div>

I do mock the extension.  
For example with Spock like

```groovy
project.extensions.add('versionCatalogs', Stub(VersionCatalogsExtension) {
   find('libs') >> Optional.of(Stub(VersionCatalog) {
      findVersion('java') >> Optional.of(Stub(VersionConstraint) {
         requiredVersion >> '4.2.3'
      })
   })
})

```

---

<div class="post-metadata">

**Author:** ![gsudheer](https://avatars.discourse-cdn.com/v4/letter/g/87869e/32.png) [@gsudheer](https://discuss.gradle.org/u/gsudheer)\
**Post date:** [June 5, 2024, 10:32pm UTC](https://discuss.gradle.org/t/projectbuilder-test-for-versioncatalog/48612/3 "2024-06-05T22:32:06Z")

</div>

Thank you very much @Vampire !

---

<div class="post-metadata">

**Author:** ![gsudheer](https://avatars.discourse-cdn.com/v4/letter/g/87869e/32.png) [@gsudheer](https://discuss.gradle.org/u/gsudheer)\
**Post date:** [June 6, 2024, 10:03pm UTC](https://discuss.gradle.org/t/projectbuilder-test-for-versioncatalog/48612/4 "2024-06-06T22:03:17Z")

</div>

Sorry for revisiting again.

When I tested using spock framework, I was getting the same exception and it is throwing near `project.pluginManager.apply("example-plugin")` we tried mock after this line.

```gradle
given:
        def project = ProjectBuilder.builder().withProjectDir(File("src/test/resources/example-default")).build()
        project.pluginManager.apply("example-plugin")

        def springCloudDependenciesVersion = "2023.0.1"

        project.extensions.add("versionCatalog", Stub(VersionCatalogsExtension) {
            find("libs") >> Optional.of(Stub(VersionCatalog) {
                findVersion("springframework-cloud") >> Optional.of(Stub(VersionConstraint) {
                    requiredVersion >> springCloudDependenciesVersion
                })
                findLibrary("spring-cloud-dependencies") >> Optional.of(Stub(DependencyConstraint) {
                    group >> "org.springframework.cloud"
                    name >> "spring-cloud-dependencies"
                    version >> springCloudDependenciesVersion
                })
            })
        })

        expect:
        project.pluginManager.hasPlugin("org.springframework.boot") == true

```

---

<div class="post-metadata">

**Author:** ![Vampire](https://sea1.discourse-cdn.com/gradle/user_avatar/discuss.gradle.org/vampire/32/9082_2.png) [@Vampire](https://discuss.gradle.org/u/Vampire)\
**Post date:** [June 7, 2024, 8:30am UTC](https://discuss.gradle.org/t/projectbuilder-test-for-versioncatalog/48612/5 "2024-06-07T08:30:43Z")

</div>

Sure, of course you have to create the extension before you call the `apply`, as your plugin is trying to access the version catalog in its `apply` method.

That’s like accessing a field before assigning a value to it and then wondering why you get a `NullPointerException`. 😉

---

<div class="post-metadata">

**Author:** ![gsudheer](https://avatars.discourse-cdn.com/v4/letter/g/87869e/32.png) [@gsudheer](https://discuss.gradle.org/u/gsudheer)\
**Post date:** [June 8, 2024, 12:48am UTC](https://discuss.gradle.org/t/projectbuilder-test-for-versioncatalog/48612/6 "2024-06-08T00:48:06Z")

</div>

Thank you @Vampire !

I think I was able to solve this finally (hopefully 🙂) . I’m using Junit5 only, so added mockito-kotlin dependency to keep my changes minimal. Spock I was not using, but first tried to see how to implement based on your input and then tried to find equivalent in mockito-kotlin.

Dependencies I used

```gradle
implementation("org.mockito.kotlin:mockito-kotlin:5.3.1")
implementation("com.moandjiezana.toml:toml4j:0.7.2")

```

```gradle
@Test
fun testPlugin() {

            val project = ProjectBuilder.builder().build()

            val filePath = this::class.java.classLoader.getResource("version-catalog/libs.versions.toml").file
            val versions = readVersionsFromTomlFile(filePath)
            val libraries = readLibrariesFromTomlFile(filePath, versions)

            val versionCatalog = createMockVersionCatalog(versions, project, libraries)
            val versionCatalogsExtension = createMockVersionCatalogsExtension(versionCatalog, "libs")

            project.extensions.add(VersionCatalogsExtension::class.java, "libs", versionCatalogsExtension)
            project.pluginManager.apply("example-plugin")

            val implementationDependencies = project.configurations.getByName(JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME).dependencies
            val hasSpringCloudDependency = implementationDependencies.any { dependency ->
                dependency.group == "org.springframework.cloud" && dependency.name == "spring-cloud-dependencies"
            }

            assertEquals(true, hasSpringCloudDependency)

            val assertPlugins = listOf("org.springframework.boot", "io.spring.dependency-management", "org.asciidoctor.jvm.convert", "com.epages.restdocs-api-spec", "org.springframework.cloud.contract")
            assertPlugins.forEach { plugin ->
                assertEquals(true, project.pluginManager.hasPlugin(plugin))
            }

        }

```

Here are the helper method

```gradle
private fun createMockVersionCatalog(versions: Map<String, String>, project: Project, libraries: Map<String, MinimalExternalModuleDependency>): VersionCatalog = mock<VersionCatalog> {
        on { findVersion(any()) }.thenAnswer { invocation ->
            val requestedVersionName = invocation.arguments[0] as String
            val version = versions[requestedVersionName]
            Optional.ofNullable(version?.let {
                mock<VersionConstraint> { on { requiredVersion }.thenReturn(version) }
            })
        }
        on { findLibrary(any()) }.thenAnswer { invocation ->
            val requestedLibraryName = invocation.arguments[0] as String
            libraries[requestedLibraryName]?.let { dependency -> Optional.of(project.provider { dependency }) }
        }
    }

    private fun createMockVersionCatalogsExtension(versionCatalog: VersionCatalog, name: String): VersionCatalogsExtension = mock {
        on { named(name) }.thenReturn(versionCatalog)
    }

    fun readVersionsFromTomlFile(filePath: String): Map<String, String> {
        val toml = Toml().read(File(filePath))
        val versionsTable = toml.getTable("versions").toMap()

        return versionsTable.mapValues { (_, value) -> value as String }
    }

    fun readLibrariesFromTomlFile(filePath: String, versions: Map<String, String>): Map<String, MinimalExternalModuleDependency> {
        val toml = Toml().read(File(filePath))
        val librariesTable = toml.getTable("libraries").toMap()

        return librariesTable.map { (libraryName, libraryToml) ->
            @Suppress("UNCHECKED_CAST")
            val libraryTable = libraryToml as Map<String, Any>
            val group = libraryTable["group"] as String
            val name = libraryTable["name"] as String
            val versionRef = libraryTable["version_ref"] as String
            val version = versions[versionRef]

            val dependency: MinimalExternalModuleDependency = mock {
                on { this.group }.thenReturn(group)
                on { this.name }.thenReturn(name)
                on { this.version }.thenReturn(version)
            }
            libraryName to dependency
        }.toMap()
    }

```

Thank you very much again for the prompt help and suggestions !

-Sudheer.
