On 02/10/2010, at 11:12 PM, Russel Winder wrote:
> Gradle clearly discriminates for JUnit and against TestNG, whereas Maven
> does not. In particular, Surefire seems to be able to pick up TestNG
> tests implicitly, whereas Gradle requires you to have:
>
> test {
> useTestNG ( )
> }
>
> in the build.gradle file. Is there any way Gradle can work this out
> instead of it having to be made explicit?
It could, but doesn't at the moment. Could you add a JIRA issue for this?
The mechanics of detecting which test frameworks to use is simple enough, I
think. However, the idea does raise some questions about how we approach
conventional work that is optional.
One question is how to deal with the configuration options for the different
test frameworks. At the moment, when you call useTestNG() the junit-specific
options are removed from the test task, and are replaced by the testng-specific
options. If instead we auto-detect which framework(s) to use, then the test
task would need to always provide the options for both. And this doesn't scale
well if we were to add more options, or support more test frameworks. It also
feels quite framework-ish, where you have a single monolithic task which can
handle any type of testing, instead of smaller, more focused building blocks
that you can assemble however you like.
One approach is to split the Test class up into a bunch of subclasses, one for
each test framework. For custom test suites, this nicely declares the test
framework and provides a namespace for the configuration options:
task integTest(type: JUnit) {
someJUnitOption = 'value'
}
task integTest(type: TestNG) {
someTestNgOption = 'value'
}
For the built-in stuff, the Java plugin would add something like the following:
task junit(type: JUnit) { ... }
task testng(type: TestNG) { ... }
task test(dependsOn: [junit, testng])
That is, 'test' becomes a lifecycle task, and the work is done by either or
both the 'junit' and 'testng' tasks. Configuration would become something like:
junit {
someJUnitOption = 'value'
}
testng {
someTestNGOption = 'value'
}
Other language plugins would possibly add additional test tasks for
language-specific test frameworks.
The problem with this approach is that most builds will end up executing a task
that never does anything, ie one of 'junit' or 'testng'. But then, this is
exactly the same problem we already have, say, for projects with no resources
or no tests or which are not distributed as a jar. We should be able to come up
with a general solution to this problem. It might be as simple as a logging
solution.
Another approach to all this would be that the Java plugin does not add any
test tasks at all, and that you need to apply a particular plugin to get unit
testing:
// Adds the main source set and implicitly the standard lifecycle but no test
task
apply plugin: 'java'
// Adds in the 'junit' task plus implicitly the test source set
apply plugin: 'junit'
// Adds in the 'testng' task plus implicitly the test source set
apply plugin: 'testng'
I think I prefer this second approach, where Gradle give you the building
blocks to compose as makes sense for your project. It's explicit and
declarative, which is always good.
The problem is that Gradle should really be able to figure this stuff out.
Maybe we need some kind of auto-detect plugin, which extracts as much
information out of the source as it can. There's all sorts of interesting
information encoded in the project's source which we could harvest to configure
the build: languages and language version, test frameworks, external
dependencies, project dependencies, whether it is a web app, and so on.
This way, you can choose either: Gradle figures out as much as it possibly can
by itself and you fill in the blanks (if any), or you tell Gradle the entire
story.
--
Adam Murdoch
Gradle Developer
http://www.gradle.org
CTO, Gradle Inc. - Gradle Training, Support, Consulting
http://www.gradle.biz