Test.single fails for test classes which have anonymous inner classes


(Bair) #1

I used the following command: gradle -Dtest.single=ServiceLifecycleTest :graphics:test And it fails thus:

javafx.concurrent.ServiceLifecycleTest$9 > initializationError FAILED

java.lang.Exception: Test class should have exactly one public constructor

This is on Gradle 1.4


(Sam Brannen) #2

I encountered the same problem (on Gradle 1.11) when trying to execute a single test within the Spring Framework test suite.

This occurs not only for anonymous inner classes but rather for any inner class. The cause of the problem is that the pattern supplied to ‘-Dtest.single=Pattern’ is expanded to ‘/Pattern*.class’ instead of just '/Pattern.class’. Note the ‘*’ between the pattern and ‘.class’.

The following output was generated by executing ‘gradle :spring-websocket:test -Dtest.single=WebSocketConfigurationTests’ against ‘master’ for the Spring Framework.

Class

Tests Failures

WebSocketConfigurationTests

6

0

WebSocketConfigurationTests$1

2

2

WebSocketConfigurationTests$2

2

2

WebSocketConfigurationTests$TestWebSocketConfigurer 2

2

WebSocketConfigurationTests$TestWebSocketHandler

2

2

In my opinion, this is a bug, since as a best practice only top-level classes should be executed as test classes.

I would argue that an inner class (and especially an anonymous inner class) is typically used only within its owning test class and is never itself a test class.

Can Gradleware please either remove the asterisk between the pattern and “.class” or provide a way to supply a pattern with full control over how the end of the class name is interpreted?


(Peter Niederwieser) #3

I cannot reproduce this with 1.11. I did a quick experiment, and test class scanning correctly filtered out inner classes, inner test classes, and nested classes that aren’t test classes. Did you perhaps set ‘test.scanForTestClasses = false’? In that case, you may have to take care of filtering out inner classes yourself (perhaps with ‘test.exclude ‘**/$’’). Also, I don’t see how this problem would be specific to the case where ‘-Dtest.single’ is used, as this just adds another filter.


(Sam Brannen) #4

Hi Peter,

Thanks for looking into this so promptly!

In the Spring Framework build, we do in fact set ‘scanForTestClasses’ to ‘false’. Thus, adding an exclusion for ‘’**/$’’ at the all-projects level serves as a viable workaround. Thanks for the tip.

Note, however, that this problem only arises when we use ‘-Dtest.single’. So in that sense, it is specific to the case where ‘-Dtest.single’ is used, at least in combination with the filters we have in place. I have not looked at the implementation in Gradle, but it would appear that the include generated for ‘-Dtest.single’ overrides any other include filters such as ‘"/*Tests.class"’ and '"/Test.class"’. As you can see from my comments above, without the explicit exclusion for ‘’**/$*’’, Gradle attempts to execute ‘WebSocketConfigurationTests$1’ as a test class.

In summary, although ‘’**/$’’ serves as viable work-around for us, I still feel that Gradle should ensure that the asterisk before ‘.class’ is non-greedy when generating the full pattern for ‘-Dtest.single’. I say non-greedy in the sense of regular expressions: the wildcard after the pattern should only match against a top-level class name; it should not eat “$*” before “.class”.

In the very least, Gradle should not pass any class references to the JUnit or TestNG test runners for classes that are not test classes (e.g., abstract classes, annotation types, concrete classes without ‘@Test’ annotations, etc.), regardless of the value of ‘scanForTestClasses’. Otherwise, builds will unavoidably break.


(Peter Niederwieser) #5

Have a look at the new ‘–test’ command line option introduced in 1.10 (see release notes). It’s set to replace ‘-Dtest.single’, and I think it doesn’t have this problem.


(Sam Brannen) #6

Hi Peter,

I’d actually already investigated the ‘–tests’ command line option before I posted here, but I gave up on it pretty quickly, since it does not appear to work at all with Spring’s build.

For example, with our current Gradle configuration in ‘master’, the following works.

gradle :spring-websocket:test -Dtest.single=WebSocketConfigurationTests

But the following fails…

gradle :spring-websocket:test --tests WebSocketConfigurationTests

… with the following output:

  • What went wrong:

Execution failed for task ‘:spring-websocket:test’.

No tests found for given includes: [WebSocketConfigurationTests]

Is the ‘–tests’ filtering not supported if ‘include’ and ‘exclude’ patterns are specified for the ‘test’ task?

By the way, these issues are all verifiable against ‘master’ for the Spring Framework, in case you want to see these things failing for yourself. :wink:

Regards,

Sam


(Peter Niederwieser) #7

Check out the release notes I linked to. ‘–tests’ doesn’t currently add any wildcards automatically.


(Sam Brannen) #8

The second example in the release notes demonstrates supplying a fully qualified class name, but that doesn’t work for us either.

gradle :spring-websocket:test --tests org.springframework.web.socket.config.annotation.WebSocketConfigurationTests

Fails with:

  • What went wrong:

Execution failed for task ‘:spring-websocket:test’.

No tests found for given includes: [org.springframework.web.socket.config.annotation.WebSocketConfigurationTests]

The following doesn’t work either:

gradle :spring-websocket:test --tests org.springframework.web.socket.config.annotation.WebSocketConfigurationTests.*

Nor does this:

gradle :spring-websocket:test --tests *WebSocketConfigurationTests

So, like I was saying, it appears that the ‘–tests’ feature does not work at all with the Gradle build configuration for Spring Framework.