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

Reply via email to