// Copyright (C) 2025 Gradle, Inc.
//
// Licensed under the Creative Commons Attribution-Noncommercial-ShareAlike 4.0 International License.;
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://creativecommons.org/licenses/by-nc-sa/4.0/
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

[[test_binary_plugins_advanced]]
= Binary Plugin Testing

Gradle provides a robust mechanism for testing binary plugins.

Gradle's <<test_kit.adoc#test_kit,`TestKit`>> allows you to programmatically execute synthetic builds that use the plugin under development, all within the plugin’s own build.

A well-tested plugin typically includes two levels of testing:

1. Unit Tests
2. Functional Tests

The directory of our plugin looks as follows:

====
[.multi-language-sample]
=====
[source, kotlin]
----
.
└── plugin
    ├── settings.gradle.kts
    ├── build.gradle.kts
    └── src
       ├── main
       │   └── java/org/example
       │       ├── FileSizeDiffTask.java
       │       ├── FileSizeDiffPlugin.java
       │       └── FileSizeDiffExtension.java
       ├── test
       │   └── java/org/example
       │       └── FileSizeDiffPluginTest.java
       └── functionalTest
           └── java/org/example
               └── FileSizeDiffPluginFunctionalTest.java
----
=====
[.multi-language-sample]
=====
[source, groovy]
----
.
└── plugin
    ├── settings.gradle
    ├── build.gradle
    └── src
       ├── main
       │   └── java/org/example
       │       ├── FileSizeDiffTask.java
       │       ├── FileSizeDiffPlugin.java
       │       └── FileSizeDiffExtension.java
       ├── test
       │   └── java/org/example
       │       └── FileSizeDiffPluginTest.java
       └── functionalTest
           └── java/org/example
               └── FileSizeDiffPluginFunctionalTest.java
----
=====
====

[[sec:unit_test]]
== 1. Unit Test

*Unit tests* validate the internal behavior of your plugin in a lightweight, isolated project.
These tests simulate applying your plugin without needing a full Gradle execution.

They test:

- The plugin applies without errors
- Tasks or extensions are registered correctly

++++
<p>
  <div style="position:relative;padding-top:56.25%;">
    <iframe src="https://www.youtube-nocookie.com/embed/kwNkBHKfmzQ?si=GR6zTm8gGEtBpw0o&rel=0" frameborder="0" allowfullscreen
      style="position:absolute;top:0;left:0;width:100%;height:100%;"></iframe>
  </div>
</p>
++++

++++
<p>
  <div style="position:relative;padding-top:56.25%;">
    <iframe src="https://www.youtube-nocookie.com/embed/Zh0Kew2y35M?si=DPloBMnDDMeWeYKD&rel=0" frameborder="0" allowfullscreen
      style="position:absolute;top:0;left:0;width:100%;height:100%;"></iframe>
  </div>
</p>
++++

The unit test for the `filesizediff` plugin looks as follows:

.src/test/java/org/example/FileSizeDiffPluginTest
[source,java]
----
include::{snippetsPath}/fundamentals/developing-plugins/fileSizeDiffBinaryPlugin/common/plugin/src/test/java/org/example/FileSizeDiffPluginTest.java[]
----

This test checks that the `org.example.filesizediff` plugin is applied and a `fileSizeDiff` task is added.

Unit tests are fast and useful for verifying the basic mechanics of your plugin logic.

[[sec:functional_test]]
== 2. Functional Test

*Functional tests* (also known as end-to-end plugin tests) use Gradle's <<test_kit.adoc#test_kit,`TestKit`>> to launch real Gradle builds in a temporary directory.
This is how you verify your plugin works correctly in real-world usage.

They test:

- The plugin can be applied to a real build
- The plugin task runs correctly and produces the expected output
- Users can configure the plugin via the DSL

++++
<p>
  <div style="position:relative;padding-top:56.25%;">
    <iframe src="https://www.youtube-nocookie.com/embed/AcuQcYuQ2uw?si=7hKCWQl5K6_L3ntQ&rel=0" frameborder="0" allowfullscreen
      style="position:absolute;top:0;left:0;width:100%;height:100%;"></iframe>
  </div>
</p>
++++

The functional test for the `filesizediff` plugin looks as follows:

.src/functionalTest/java/org/example/FileSizeDiffPluginFunctionalTest.java
[source,java]
----
include::{snippetsPath}/fundamentals/developing-plugins/fileSizeDiffBinaryPlugin/common/plugin/src/functionalTest/java/org/example/FileSizeDiffPluginFunctionalTest.java[]
----

`GradleRunner` is the core API provided by `TestKit` for executing builds in a test environment.
`GradleRunner` simulates a Gradle invocation.
Each test creates a temporary project with a `build.gradle` file, input files, and runs the plugin task using `GradleRunner`.

Unlike unit tests in `src/test/java` that test individual classes, functional tests live in `src/functionalTest/java` and verify that your plugin behaves correctly in a real build.
Gradle doesn’t automatically recognize custom test source sets, so you need to declare a `functionalTest` source set and configure a task to run it.

Fortunately, `gradle init` can scaffold this setup for you:

====
include::sample[dir="snippets/fundamentals/developing-plugins/fileSizeDiffBinaryPlugin/kotlin", files="plugin/build.gradle.kts[]"]
include::sample[dir="snippets/fundamentals/developing-plugins/fileSizeDiffBinaryPlugin/groovy", files="plugin/build.gradle[]"]
====

[[sec:consumer_project]]
== Consumer Project

You can optionally create a consumer project that uses your plugin:

====
[.multi-language-sample]
=====
[source, kotlin]
----
.
├── settings.gradle.kts // Include custom plugin
├── build.gradle.kts    // Applies custom plugin
│
└── plugin
    ├── settings.gradle.kts
    ├── build.gradle.kts
    └── src
       ...
----
=====
[.multi-language-sample]
=====
[source, groovy]
----
.
├── settings.gradle // Include custom plugin
├── build.gradle    // Applies custom plugin
│
└── plugin
    ├── settings.gradle
    ├── build.gradle
    └── src
       ...
----
=====
====

++++
<p>
  <div style="position:relative;padding-top:56.25%;">
    <iframe src="https://www.youtube-nocookie.com/embed/p84BiAMS8e8?si=KxL30KuM8ezbnOlJ&rel=0" frameborder="0" allowfullscreen
      style="position:absolute;top:0;left:0;width:100%;height:100%;"></iframe>
  </div>
</p>
++++

First you can point to the plugin as an included build in the `consumer` settings file:

====
include::sample[dir="snippets/fundamentals/developing-plugins/fileSizeDiffBinaryPlugin/kotlin", files="settings.gradle.kts[]"]
include::sample[dir="snippets/fundamentals/developing-plugins/fileSizeDiffBinaryPlugin/groovy", files="settings.gradle[]"]
====

Then in the build file of the `consumer` project, you apply the plugin and test it:

====
include::sample[dir="snippets/fundamentals/developing-plugins/fileSizeDiffBinaryPlugin/kotlin", files="build.gradle.kts[]"]
include::sample[dir="snippets/fundamentals/developing-plugins/fileSizeDiffBinaryPlugin/groovy", files="build.gradle[]"]
====

In the `consumer` project, you can create dummy `a.txt` and `b.txt` files and run `./gradlew fileSizeDiff`:

[source,bash]
----
$ ./gradlew fileSizeDiff
----
[source,text]
----
include::{snippetsPath}/fundamentals/developing-plugins/fileSizeDiffBinaryPlugin/tests/fileSizeDiff.out[]
----

[.text-right]
**Next Step:** <<publishing_binary_plugin_advanced.adoc#publish_binary_plugins_advanced,Learn how to publish Binary Plugins>> >>
