Integration tests pass when they should not

I’m using the jvm-test-suit plugin to configure integration tests, similar to what’s shown in The JVM Test Suite Plugin. I use Arquillian and ShrinkWrap to run them. However, I noticed that once injections (@Inject) are used, the tests pass automatically, even if they should fail (assertTrue(false)). This is because the injections fail. There are a lot of posts about this symptom, but the causes are varied.

I don’t know if the problem comes from Gradle, Arquillian, or ShrinkWrap (which uses the Gradle resolver through the Gradle API Toolings), but in an effort to eliminate causes, I’m asking for someone to have a look at this minimal project. It has one empty bean and one test class that injects that bean. The test can be run with ./gradlew :lib:integrationTest and will pass (wrong behavior). If the injection is commented out, it will fail correctly.

testArq.zip (127.9 KB)

Note that the arquillian.xml points to the Wildfly location, which should be changed according to the environment. It can be downloaded from WildFly Downloads.

If I can be told if the problem is in Arquillian or the ShrinkWrap resolver it will also help a lot.

Thanks

It’s not really the injection that is the problem.
If you just comment the @Inject it shows the exact same behavior.

When Jupiter tries to load your test class it throws this exception as the Service class is not found:

java.lang.NoClassDefFoundError: testArq/Service
	at java.base/java.lang.Class.getDeclaredFields0(Native Method)
	at java.base/java.lang.Class.privateGetDeclaredFields(Class.java:3297)
	at java.base/java.lang.Class.getDeclaredFields(Class.java:2371)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.commons.util.ReflectionUtils.getDeclaredFields(ReflectionUtils.java:1470)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.commons.util.ReflectionUtils.findAllFieldsInHierarchy(ReflectionUtils.java:1200)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.commons.util.ReflectionUtils.findFields(ReflectionUtils.java:1188)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.jupiter.engine.descriptor.ExtensionUtils.registerExtensionsFromFields(ExtensionUtils.java:96)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.prepare(ClassBasedTestDescriptor.java:150)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.prepare(ClassBasedTestDescriptor.java:80)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$2(NodeTestTask.java:123)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:123)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:90)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.jboss.arquillian.junit5.container.JUnitJupiterTestRunner.execute(JUnitJupiterTestRunner.java:57)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.jboss.arquillian.protocol.servlet5.runner.ServletTestRunner.executeTest(ServletTestRunner.java:139)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.jboss.arquillian.protocol.servlet5.runner.ServletTestRunner.execute(ServletTestRunner.java:117)
	at deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war//org.jboss.arquillian.protocol.servlet5.runner.ServletTestRunner.doGet(ServletTestRunner.java:86)
	at jakarta.servlet.api@6.0.0//jakarta.servlet.http.HttpServlet.service(HttpServlet.java:527)
	at jakarta.servlet.api@6.0.0//jakarta.servlet.http.HttpServlet.service(HttpServlet.java:614)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
	at org.wildfly.security.elytron-web.undertow-server@4.0.0.Final//org.wildfly.elytron.web.undertow.server.ElytronRunAsHandler.lambda$handleRequest$1(ElytronRunAsHandler.java:68)
	at org.wildfly.security.elytron-base@2.2.3.Final//org.wildfly.security.auth.server.FlexibleIdentityAssociation.runAsFunctionEx(FlexibleIdentityAssociation.java:103)
	at org.wildfly.security.elytron-base@2.2.3.Final//org.wildfly.security.auth.server.Scoped.runAsFunctionEx(Scoped.java:161)
	at org.wildfly.security.elytron-base@2.2.3.Final//org.wildfly.security.auth.server.Scoped.runAs(Scoped.java:73)
	at org.wildfly.security.elytron-web.undertow-server@4.0.0.Final//org.wildfly.elytron.web.undertow.server.ElytronRunAsHandler.handleRequest(ElytronRunAsHandler.java:67)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:117)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
	at io.undertow.core@2.3.12.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at io.undertow.core@2.3.12.Final//io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
	at io.undertow.core@2.3.12.Final//io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
	at org.wildfly.security.elytron-web.undertow-server-servlet@4.0.0.Final//org.wildfly.elytron.web.undertow.server.servlet.CleanUpHandler.handleRequest(CleanUpHandler.java:38)
	at io.undertow.core@2.3.12.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at org.wildfly.extension.undertow@31.0.1.Final//org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:44)
	at io.undertow.core@2.3.12.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at org.wildfly.extension.undertow@31.0.1.Final//org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:51)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.SendErrorPageHandler.handleRequest(SendErrorPageHandler.java:52)
	at io.undertow.core@2.3.12.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:276)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:135)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:132)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
	at org.wildfly.extension.undertow@31.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1413)
	at org.wildfly.extension.undertow@31.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1413)
	at org.wildfly.extension.undertow@31.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1413)
	at org.wildfly.extension.undertow@31.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1413)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:256)
	at io.undertow.servlet@2.3.12.Final//io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:101)
	at io.undertow.core@2.3.12.Final//io.undertow.server.Connectors.executeRootHandler(Connectors.java:393)
	at io.undertow.core@2.3.12.Final//io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:859)
	at org.jboss.threads@2.4.0.Final//org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
	at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1990)
	at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1486)
	at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1348)
	at org.jboss.xnio@3.8.13.Final//org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1282)
	at java.base/java.lang.Thread.run(Thread.java:840)
Caused by: java.lang.ClassNotFoundException: testArq.Service from [Module "deployment.786f5493-fa58-40d7-b59d-ad408628bcfb.war" from Service Module Loader]
	at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:200)
	at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:410)
	at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:398)
	at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:116)
	... 83 more

The exception is reported as test failure on the CONTAINER node, which is the test class.
But the org.jboss.arquillian.junit5.container.JUnitJupiterTestRunner.ArquillianTestMethodExecutionListener ignores this as it only listens for results from the actual test nodes and thus ignores the failure, swallowing the problem.

1 Like

Thanks for the help! How did you get this stack trace? It didn’t appear for me.

Any idea what would cause the class to not be found? Sounds like ShrinkWrap isn’t including everything it needs to, though the test suit defines implementation(project()), which should include Service.

I also tried to remove the use of the test suit plugin and moved the contents of integrationTest to test since that one is created for me by the java plugin. So with “dumb old Gradle”:

tasks.withType(Test).configureEach {
	useJUnitPlatform()
}

dependencies {
	providedCompile("jakarta.platform:jakarta.jakartaee-api:$jakartaVersion")
	
	testImplementation("org.junit.jupiter:junit-jupiter:$junitVersion")
	testRuntimeOnly("org.junit.platform:junit-platform-launcher:$junitPlatformVersion")

//	testImplementation(project(path)) // tried with and without this
	testImplementation("org.jboss.arquillian.junit5:arquillian-junit5-container:$arquillianVersion")
	testImplementation("org.jboss.arquillian.protocol:arquillian-protocol-servlet-jakarta:$arquillianServletProtocolVersion")
	testImplementation("org.wildfly.arquillian:wildfly-arquillian-container-managed:$arquillianWildflyContainerVersion")
	testImplementation("org.jboss.shrinkwrap.resolver:shrinkwrap-resolver-gradle-depchain:$shrinkwrapResolverVersion")
}

I got the same behavior.

(And yes, Groovy, not Kotlin… we’ll get there)

Had a look at what ShrinkWrap produces:

+---META-INF
|       MANIFEST.MF
|
+---testArq
|       Service.class
|
\---WEB-INF
    |   beans.xml
    |
    +---classes
    |   \---testArq
    |           ServiceTest.class
    |
    \---lib
            arquillian-core.jar
            arquillian-jakarta-servlet-protocol.jar
            arquillian-junit5.jar
            arquillian-testenricher-cdi-jakarta.jar
            arquillian-testenricher-ejb-jakarta.jar
            arquillian-testenricher-initialcontext.jar
            arquillian-testenricher-resource-jakarta.jar
            wildfly-common-testencricher.jar

So Service is there, but not inside WEB-INF, which is my guess as to why it doesn’t get picked up. The way ShrinkWrap creates the war is with the Gradle importer (it’s inside the sample project):

return ShrinkWrap.create(EmbeddedGradleImporter.class)
	.forThisProjectDirectory()
	.importBuildOutput()
	.as(WebArchive.class);

which uses the Gradle tooling under the hood (resolver/gradle at master · shrinkwrap/resolver · GitHub, specifically I believe it’s resolver/gradle/impl-gradle-embedded-archive/src/main/java/org/jboss/shrinkwrap/impl/gradle/archive/importer/embedded/EmbeddedGradleImporterImpl.java at master · shrinkwrap/resolver · GitHub). So again I’m not sure if it’s ShrinkWrap (my suspicioun) or the Gradle tool it calls. Probably won’t hurt to ask them.

Adding the line .addClass(Service.class); to the ShrinkWrap resolver adds the file under

\---WEB-INF
    |   beans.xml
    |
    +---classes
    |   \---testArq
    |           ServiceTest.class
    |           Service.class

And now the test fails properly. However, this is not a solution for a non-minimal project.

Thanks for the help! How did you get this stack trace? It didn’t appear for me.

Debugger :slight_smile:

Sounds like ShrinkWrap isn’t including everything it needs to, though the test suit defines implementation(project()), which should include Service.

Afair the intention of Arquillian folks is, that you use shrinkwrap to add all production and test classes need for that test case, so that you produce a minimal deployment. We are work build our full deployment and just add in the test classes and use a plugin that only deploys once for several tests instead for every test. Both has its pros and cons as always. But that is not a Gradle topic actually. :slight_smile:

I also tried to remove the use of the test suit plugin and moved the contents

No, you did not. :smiley:
It is also just one of those test suites it is just registered and configured for you by the Java plugin.

Debugger :slight_smile:

Yes, I used it, but maybe I didn’t debug the right place. I was focused on the injection failing :confused:

Afair the intention of Arquillian folks is, that you use shrinkwrap to add all production and test classes need for that test case, so that you produce a minimal deployment. We are work build our full deployment and just add in the test classes and use a plugin that only deploys once for several tests instead for every test. Both has its pros and cons as always.

Yes, that’s what Arq+SW are supposed to do. The way you do it seems equivalent to me. The deployment happens once for all tests, like in your case, if one uses the Arquillian Suite Extension GitHub - ingwarsw/arquillian-suite-extension: Arquillian extension that will force single deployment for all tests. Otherwise these tests take O(10) times longer at the very least, in my experience.

But that is not a Gradle topic actually. :slight_smile:

I agree :grin:

No, you did not. :smiley:
It is also just one of those test suites it is just registered and configured for you by the Java plugin.

Well, I meant that I removed the jvm-test-suit plugin and the whole associated configuration block

plugins {
    id "java"
    id "war"
//    id "jvm-test-suite"
}
...
//testing {
//    suites {
...

I understand that the Java plugin actually creates the test suit for me, but I was trying to eliminate the possibility that the plugin was not playing nice with ShrinkWrap. Turned out not to be the case, which is not surprising.

Anyway, thanks again Vampire! I’ll take this to ShrinkWrap.

The deployment happens once for all tests, like in your case, if one uses the Arquillian Suite Extension

Yes, that’s what what we use.

Otherwise these tests take O(10) times longer at the very least, in my experience.

If you build a full deployment and it is big, yes. If you build minimal deployments like intended by Arquillian folks, the deployment also works much faster. But then it is further away from the production environment. As I said, all have its pros and cons.

Well, I meant that I removed the jvm-test-suit plugin […] I was trying to eliminate the possibility that the plugin was not playing nice with ShrinkWrap.

And I said no, you didn’t.
You removed the useless no-operation line id "jvm-test-suite". But as the plugin is applied by Java plugin already, that line has no effect anyway.