jjohannes / gradle-plugins-howto

How to write Gradle plugins - answers to common questions and alternative implementation solutions
Apache License 2.0
130 stars 6 forks source link

How to create an example project and write tests for it? #4

Open ryantheleach opened 1 month ago

ryantheleach commented 1 month ago

I'm attempting to fork https://github.com/PeppsHabender/r4j/ in order to customize the functionality and fix some bugs.

As part of this, I'm trying to add a Test/Sample project under the repository, without changing the existing structure too much.

It is my intention, that this folder can both be used to show people how to use the plugin, and therefore have 'standard' dependencies that can be copied, and be used to do manual (and maybe) automatic integration testing.

I've seen conflicting reports on whether to use a composite build, or a sub-project, and I'm also not sure that my goals are technically compatible with each other.

Goals:

  1. Keep the structure similar, so that a PR is likely to be accepted. (flexible if it breaks gradle conventions too badly)
  2. Have a folder inside the repository, 1 level from the root, that can show people how to use it. (and have it show up in the side bar of intelliJ where gradle projects are synced)
  3. Create an integration test, that can easily pull in updated changes to the plugin code as I'm testing.

My understanding is a composite build is ideal for this scenario, as it can override the individual settings of the sample project, but I'm unsure how to structure it, given the requirement of having it below the root folder, instead of being a sibling.

My gut feeling is that it would be better to take the entire repo root, and chuck it in a sub-folder alongside the sample project, and that my goal of not changing the structure is moot.

jjohannes commented 2 weeks ago

IIIUC, you would like to create an example project that uses the io.github.peppshabender.r4j Gradle plugin from source. And then write a test that does some assertions based on that example project.

To do that, the example project needs to be a separate Gradle build. It is not possible to have an example and the plugin that is used in it as subprojects of the same build.

It is not a problem to have this separate build as a subfolder in the existing repository. For example:

r4j-gradle-example
├── settings.gradle.kts  <-- this makes it a separate build
├── build.gradle.kts
└── ...

If you want this project to works as example that uses the plugin from source, you add includeBuild("..") to the settings.gradle.kts of the example. Then you can use the plugin inside the build.gradle.kts. And run builds from inside the r4j-gradle-example folder or open that folder in IntelliJ.

I would put a test that uses the project into r4j-gradle-plugin/src/test/kotlin using whatever test framework you desire. And then treat the example as "test data" there. Then you use Gradle's TestKit to load and run builds on the project. For example:

    @Test
    fun `example test`() {
        val exampleProject = File("../r4j-gradle-example") // or first copy the example to a tmp folder and run the build there

        val result = GradleRunner.create().forwardOutput().withPluginClasspath()
            .withProjectDir(exampleProject)
            .withArguments("build")
            .build()

        assertThat(result.task(":build")?.outcome).isEqualTo(SUCCESS)
        assertThat(File(exampleProject, "build")).isDirectory()
    }