The answer is through a custom org.testng.IMethodSelector:
Its includeMethod() can exclude any method we want, like a public not-annotated method.
However, to register a custom Java MethodSelector, you must add it to the XMLTest instance managed by any TestRunner, which means you need your own custom TestRunner.
But, to build a custom TestRunner, you need to register a TestRunnerFactory, through the -testrunfactory option.
BUT that -testrunfactory is NEVER taken into account by TestNG class... so you need also to define a custom TestNG class :
- in order to override the configure(Map) method,
- so you can actually set the TestRunnerFactory
- TestRunnerFactory which will build you a custom TestRunner,
- TestRunner which will set to the XMLTest instance a custom XMLMethodSelector
- XMLMethodSelector which will build a custom IMethodSelector
- IMethodSelector which will exclude any TestNG methods of your choosing!
Ok... it's a nightmare. But it is also a code-challenge, so it must be a little challenging ;)
All the code is available at DZone snippets.
As usual for a code challenge:
- one java class (and quite a few inner classes)
- copy-paste the class in a 'source/test' directory (since the package is 'test')
- run it (no arguments needed)
Update from Mike Stone:
I'm going to accept this because it sounds pretty close to what I ended up doing, but I figured I would add what I did as well.
Basically, I created a Groups annotation that behaves like the groups property of the Test (and other) annotations.
Then, I created a GroupsAnnotationTransformer, which uses IAnnotationTransformer to look at all tests and test classes being defined, then modifies the test to add the groups, which works perfectly with group exclusion and inclusion.
Modify the build to use the new annotation transformer, and it all works perfectly!
Well... the one caveat is that it doesn't add the groups to non-test methods... because at the time I did this, there was another annotation transformer that lets you transform ANYTHING, but it somehow wasn't included in the TestNG I was using for some reason... so it is a good idea to make your before/after annotated methods to alwaysRun=true... which is sufficient for me.
The end result is I can do:
@Groups({ "myGroup1", "myGroup2"})
public class MyTestCase {
@Test
@Groups("aMethodLevelGroup")
public void myTest() {
}
}
And I made the transformer work with subclassing and everything.