I want to create a gradle plugin for my kotlin bas...
# plugin-development
c
I want to create a gradle plugin for my kotlin based test framework, and I want it to work with gradles test reporting and with the newTestLauncher() api. should I inherit from org.gradle.api.tasks.testing.Test ? I don’t want to use gradles useJunitPlatform().
v
Why do you not want to make it a JUnit Platform or at least some JUnit Platform bridge? This is extremely handy, as then any tool that supports JUnit 5 supports your testframework, including Gradle, IDEs, build servers, ...
c
I already have a junit 5 platform engine, but I want a plugin that offers more than i can do with junit engine. what is a junit Platform Bridge?
I just want to explore what i can do when not tied to junit engine and the way that gradle’s useJunitPlatform interacts with it. what would be the best way to do that? can I implement my own
TestFramework
?
v
what is a junit Platform Bridge
Not an official term. I meant like vintage engine that can run JUnit 4 tests, or testng engine that can run TestNG tests. If your framework already is a JUnit 5 engine, forget that part. 🙂
can I implement my own
TestFramework
?
As far as I know, no, only the built-in frameworks, but through having a JUnit platform engine, practically any framework is supported. What is it, that you do not like with using the platform integration?
c
one example is that in my engine i run the tests at discovery time so any filtering would have to happen already at discovery time. my engine works fine with gradle but --tests … does not work so well as it could. I would like to parse the --test parameter myself and translate it to junit engine calls. I could also just wrap gradles junit platform engine and put the --test parameter into a system prop.
but thats just one example. the main reason is I just care about every detail of the UX of my test runner and I want full control.
I could extend DefaultTask, but can I then plug into the test reporting to support gradle test report plugins?
v
Maybe running the tests at discovery time is not really the best idea actually. Probably also is then awkward with other situations / integrations. If you cannot determine the tests at discovery time without running them, you should probably more register them at runtime. In Spock with data driven tests for example, we also cannot tell at discovery time all tests which exist, as this can only be determined at test runtime. As I said, afair, there is no real good way to do it in Gradle like you intend. You probably would have to use quite some internals if it is possible at all, which I'm not sure of. One way - even though a bit ugly - might be to have your custom task that executes the tests and then a second task that is a normal
Test
task and runs a JUnit 5 platform that does not actually execute the tests, but just parses the result files of your custom task and reports the test results.
1
c
ok thats not a problem, I just wanted to make sure I know all options before I start.
so DefaultTask is the correct thing to inherit from?
v
If you want a complete own task, I'd say so, yes. If you want to use something from
Test
and also want things like
tasks.withType<Test>().confiugreEach { ... }
to match it, you could of course also inherit from that
c
ok because AbstractTestTask has this Note: This abstract class is not intended for implementation by build script or plugin authors. so I was wondering if thats also true for
Test
v
I guess this is because of the two methods that return internal classes. If you subclass
Test
without overwriting those methods, I'd guess it is ok, especially if that class does not have such a note. But this is really just educated guessing by me.
c
the gradle codebase is really full of implementation inheritance. Test should just be an interface. and not an abstract class.
v
Why? It is a task class, what could be a reason to make it an interface?
c
n/m not going to open that can of worms 🙂
v
Well, not my fishing party anyways 😄
c
the abstract reason is implementation inheritance is bad, and one practical example is that I cannot say something is a test (and works with
tasks.withType<Test>().confiugreEach { ... }
without inhertiting from the test task impl
v
But, well, it is not an interface defining some API, it is a concrete test class. Imho it is perfectly right that it is a class. But anyway, you would need to convince the Gradle folks from the opposite, not me. 😄
c
btw, is it true that classes that implement gradle tasks need to be
open
I have seen that claim in some open source plugins but i can’t find docs that say it.
v
"need to be" is too strong, as you can always create instances of domain objects yourself and give them to Gradle. "should be" definitely. Open or abstract. I prefer abstract and leaving out all the boilerplate that Gradle can add automatically. If you let Gradle create any domain object it creates a
..._Decorated
subclass where it did is magic. This also includes that all such classes automatically implement
ExtensionAware
even if not declared explicitly, which imho is reason enough to declare it explicitly, then someone wanting to use it does not need to cast unsafely. (Of course not for tasks, they already declare it, but for example for extensions and anything else Gradle instantiates for you.
https://docs.gradle.org/current/userguide/implementing_custom_tasks.html for example says "It’s also beneficial to make our task class abstract because Gradle will handle many things automatically" Dunno whether the "open" is also mentioned somewhere, but latest when you try to let Gradle create it, you should get a pretty blatant complaint. :-D
c
Thanks!
👌 1