Gradle integration problem
Hi,
sadly I can't get gradle + testfx to work. I already implemented testFx in eclipse and my tests do work fine. Though in gradle it throws me the NoNodeFoundException on my GUI elements in my test class. Maybe I got something wrong with my dependencies? I tried many combinations with no success.
apply plugin: 'java' apply plugin: 'maven' apply plugin: 'checkstyle' apply plugin: 'application' apply plugin: 'jacoco'
group = 'TodoManager' version = '0.0.1' description = """Aufgabenplanung""" mainClassName = "todomanager.model.ReadAndWrite"
defaultTasks 'clean', 'test', 'build', 'jacocoTestReport','distZip','javadoc','wrapper'
repositories {
maven { url "http://repo.maven.apache.org/maven2" } jcenter() mavenCentral() }
jar { baseName = 'TodoManager' version = '0.5.0' }
dependencies {
/* testCompile group: "org.loadui", name: "testFx", version: "3.1.2" testCompile "org.testfx:testfx-core:4.0.+" testCompile "org.testfx:testfx-junit:4.0.+" compile files('lib/TodoManagerLibrary-1.1.jar') testCompile 'junit:junit:4.+' */ testCompile group: "org.loadui", name: "testFx", version: "3.1.2" testCompile "junit:junit:4.10" testCompile "org.testfx:testfx-core:4.0.+" testCompile "org.testfx:testfx-legacy:4.0.+", { exclude group: "junit", module: "junit" } }
checkstyle { sourceSets = [sourceSets.main] }
jacoco { toolVersion = "0.7.1.201405082137" reportsDir = file("$buildDir/reports/jacoco") }
jacocoTestReport { reports { xml.enabled false csv.enabled false html.destination "$buildDir/reports/jacoco/html" } classDirectories = files('build/classes/') }
test {
jacoco {
append = false
destinationFile = file("$buildDir/jacoco/jacocoTest.exec")
classDumpFile = file("$buildDir/jacoco/classpathdumps")
}
}
Hi,
I'm using TestFX with gradle and eclipse. Both work fine. Can you tear down the error any further (Stacktrace etc.)?
Basically I assume that when it works in eclipse, the reason might be the class path. Are you using the 3.1.2 version in parallel to 4.0.x? I assume the legacy part should adress this. Here is a snippet of my gradle dependencies using TestFx (using gradle 2.12). You may just try this first, before doing more debugging.
testCompile (
//...
[group: "org.testfx", name: "testfx-core", version: "4.0.4-alpha"],
[group: "org.testfx", name: "testfx-junit", version: "4.0.4-alpha"]
)
If that doesn't help, just check the libraries included in eclipse and try to use exactly the same in gradle.
Hi,
I have a similar problem. My tests run perfectly fine in intellij, but fail when run through gradle.
The code I used for the tests is the ContactsSampleTest code, given in #57 by hastebrot, except I added
@BeforeClass
public static void setUp() {
Platform.setImplicitExit(false);
}
so it won't fail in intellij when I run multiple tests (however, the same excpetion occurs whether I use it or not).
I get the following exception:
java.util.concurrent.TimeoutException: FX Application Thread not running
at org.testfx.api.FxToolkit.cleanupApplication(FxToolkit.java:173)
at org.testfx.framework.junit.ApplicationTest.internalAfter(ApplicationTest.java:56)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:33)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:114)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:57)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:66)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
at sun.reflect.GeneratedMethodAccessor72.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
at com.sun.proxy.$Proxy1.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:108)
at sun.reflect.GeneratedMethodAccessor71.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:146)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:128)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
at java.lang.Thread.run(Thread.java:748)
My gradle file looks like this:
version '1.0-SNAPSHOT'
apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'idea'
apply plugin: 'jacoco'
apply plugin: 'javafx-gradle-plugin'
mainClassName = 'app.Main'
sourceCompatibility = 1.8
buildscript {
dependencies {
classpath group: 'de.dynamicfiles.projects.gradle.plugins', name: 'javafx-gradle-plugin', version: '8.8.2'
}
repositories {
mavenLocal()
mavenCentral()
}
}
repositories {
mavenLocal()
mavenCentral()
flatDir {
dirs 'libs'
}
}
jacoco {
toolVersion = "0.8.0"
}
dependencies {
testCompile "org.testfx:testfx-core:4.0.12-alpha"
testCompile "org.testfx:testfx-junit:4.0.12-alpha"
testCompile group: 'junit', name: 'junit', version: '4.12'
//some more...
}
jfx {
mainClass = 'app.Main'
vendor = 'MyName'
}
I'm running it on macOS Sierra 10.12.6
Any help would be appreciated.
Why are you setting the implicit exit to false? Is the test working, when you comment this line?
Otherwise: The exception says, that the FX-Application Thread has not been started or has been killed during the test.
Is this the only exception you see, or are there more?
If there aren't more, can you add the following line to the end of each test:
try{WaitForAsyncUtils.checkException();}
catch(Exception e){e.printStacktrace();}
@Cappuccino90 @domfran I don't see Monocle included in your dependencies for TestFX 0.4.x. That could potentially be the reason why it's not working...?
Hi,
Thanks for your reply. If I don't set the implicit exit to false, all tests except the first fail in Intellij (no matter which test is first). But it makes no difference in gradle, I get the same exception with or without it.
All exceptions are the same. I tried adding those lines, but it still fails with the same exceptions.
@JordanMartinez thanks, I tried adding testCompile "org.testfx:openjfx-monocle:8u76-b04, but the issue persists.
There shouldn't be a need to set implicit exit to false in the first instance (this is already done internally in the FXToolkit).
I just copied your gradle script and the test code (without the extra implicitExit, removed the hasText() matchers it was removed from NodeMatchers package 4.0.12). It runs on my machine (one test is failing, but no exception). Also a mac (10.13.3) with Sun JDK (1.8.0_111-b14). Which java version are you using?
I would suggest the following procedure to narrow down what is happening:
Use your GUI version (debugging is easier). Remove the Platform.setImplicitExit(false) to make it fail on the second test case.
As the change you made shouldn't actually change anything, but makes your test work somehow, there might be a timing issue. As I mentioned before, the implicit exit should be set by TestFX, so first we need to verify, that this did happen. Add the following line at the beginning of each test:
System.out.println(Platform.isImplicitExit());
This should print out false.
In case it returns true, a timing issue might be the reason. Let's try a manual fix first. In eclipse you can cmd+click to go to the source of a definition (there must be a similar function in intellij). Go to the source of ApplicationTest (the base class of your test). In the method internalBefore go to the source of FxToolkit.registerPrimaryStage(). Set a breakpoint at the line Platform.setImplicitExit(false);.
Now debug your test. When the breakpoint is reached check that a Thread with name "JavaFX Application Thread" is running. And continue. If the console output is false now, then it is a timing issue.
If you can't do the procedure above for some reason, you might also add the following lines of code at the beginning of each test:
try {Thread.sleep(1000);}
catch(Exception e) {}
Platform.setImplicitExit(false);
But you should test this with the gradle build...
When running the test with gradle, System.out.println(Platform.isImplicitExit()) doesn't seem to output anything. When using the debugger as suggested above, it outputs false after verifying that JavaFX Application Thread is running for the first test, and when running the other tests, JavaFX Application Thread is not on the list of threads.
Which vendor and version of Java you are running?
This is a very strange behaviour, as the flag is correctly set in the first test and your fix for the IDE does only set this very flag before the class is loaded.
java version 1.8.0_152, vendor is Oracle.
Which build version (the number after the "b")?
Just tried with 1.8.0_152-b16 and it works too.
1.8.0_152-b16. The problem is somewhere in my project. I tried to create a clean project with the same gradle file and test file and it works fine.
I managed to find what is causing ContactsSampleTest and some of my GUI's tests to fail. It's the equals contract test using EqualsVerifierfor a completely unrelated class. For some reason, when I comment it out it just works. I guess I can find a workaround, although I use it for another class and it doesn't seem to cause any issues there. Very strange.
However, my own GUI still throws similar excpetions for some tests, but not all:
java.lang.RuntimeException: java.lang.IllegalStateException: Not on FX application thread; currentThread = Test worker
at org.testfx.util.WaitForAsyncUtils.---- Delayed Exception: (See Trace Below) ----(WaitForAsyncUtils.java:0)
Caused by: java.lang.IllegalStateException: Not on FX application thread; currentThread = Test worker
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:279)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423)
at javafx.scene.Parent$2.onProposedChange(Parent.java:367)
at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:113)
at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:108)
at com.sun.javafx.scene.control.skin.LabeledSkinBase.updateChildren(LabeledSkinBase.java:575)
at com.sun.javafx.scene.control.skin.LabeledSkinBase.handleControlPropertyChanged(LabeledSkinBase.java:204)
at com.sun.javafx.scene.control.skin.LabelSkin.handleControlPropertyChanged(LabelSkin.java:49)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase.lambda$registerChangeListener$61(BehaviorSkinBase.java:197)
at com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler$1.changed(MultiplePropertyChangeListenerHandler.java:55)
at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:89)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:182)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.StringPropertyBase.fireValueChangedEvent(StringPropertyBase.java:103)
at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:110)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:144)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:49)
at javafx.beans.property.StringProperty.setValue(StringProperty.java:65)
at javafx.scene.control.Labeled.setText(Labeled.java:145)
The exceptions occuring asynchronous to the test thread are stored internally by TestFx. Whenever you call a asynch method those exceptions are checked and thrown on your test thread. So they can even occur in other test cases. That's why I asked you to add the checkExceptions() method (it queries exactly these exceptions). As it didn't fetch any and there was no console output of any other exception as you said, I assume this wasn't your original problem.
Now to your current exception. It tells you that a object, that is supposed to be accessed on the FX-Thread (namely a Property via setText of a Label) is accessed on a different Thread (the TestThread). This is what the interact() methods in TestFX are for. You should check, if you set the text of a Label in one of the test cases (actually the line should be in the trace, is this the complete trace?). If so, you should wrap it like this:
interact(()->label.setText("hello world"));
PS: What is the meaning of EqualsVerifier? I didn't get that...
Thank you very much, interact() did help with the second type of exceptions.
And sorry, I'm new with this and didn't know I need to add showStandardStreams = true to my gradle file. So I uncommented the test causing the exception, and added checkExceptions(), and it does output false for every test.
EqualsVerifier is for testing equals+hashCode .
No Problem. Everything working now?
Yes, as long as I comment out that one test. Thanks for all your help!
Sorry, I'm losing a bit the scope.
What is the remaining Problem (Exception etc.)? Can you post the test method of the failing test?
This test is causing the exception in my first post:
public class SomeUnrelatedClassTest {
//some tests...
@Test
public void equalsContract() {
EqualsVerifier.forClass(SomeUnrelatedClass.class)
.verify();
}
}
This test is in some other class, unrelated to my GUI tests, but it causes all the TestFX tests to fail, as described in my first post. When I comment out this test, everything works fine.