New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Test classes appear to affect each other #173
Comments
Hi!
The
I assume you use FxToolkit.setupStage((stage) -> { stage.close() }) There once was a similar hanging test that had to be Platform.runLater(() -> stage.close());
[1] Line 72 in 745817c
Update: Here is the commit that fixed the hang. a1119eb516. |
Perfect! I'll convert it to Platform until your next snapshot release. If you want to look into inducing the npe, look at the commit I made last night to graphing-experiments after posting this. Remove the AfterClass handling in the Stage Test to induce the behaviour |
|
Related to #152. |
Right, I may have worded that comment weird, I was on my phone. It looks like if you intend to make the stage visible as part of your test, you'll need to manually handle closing that stage during test cleanup (which is fine, that makes enough sense). Tt looks like my second test should be able to run once I implement the Platform workaround. I expect the NPE is somehow related to the leftover stage, because I still see the stage when the scene UI controls appear for the test. |
So I tried using Platform#runLater() like you said.I tried a few different ways of getting the scene (setting it as a class variable, getting it through the FxService...) and all ways led to another hang. This time the hang got past FxToolkt#setUpStage(), but hung on FxToolkit#setUpSceneRoot(). Sorry I can't supply more. I'll push to graphing-experiments right after posting this with my updates |
I experimented a bit with @After
public void cleanup() throws Exception {
WaitForAsyncUtils.waitForFxEvents();
setupStage((stage) -> stage.close());
}
@Test
public void should_wait_for_events() {
WaitForAsyncUtils.waitForFxEvents();
sleep(1000);
} Here is the doc string for
Here is some implementation detail: private static void blockFxThreadWithSemaphore() {
Semaphore semaphore = new Semaphore(0);
runOnFxThread(semaphore::release);
try {
semaphore.acquire();
}
catch (InterruptedException ignore) {}
}
|
Workaround: One thing you can do is to @After
public void cleanup() throws Exception {
WaitForAsyncUtils.waitForFxEvents(); // not part of the workaround. called to force the deadlock.
sleep(1000);
setupStage((stage) -> stage.close());
} |
Here is a complete bug case: package org.testfx.cases.bug;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.layout.Region;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.testfx.api.FxToolkit.setupStage;
public class StageDeadlockTest extends FxRobotTestBase {
@Before
public void setup() throws Exception {
setupStage((stage) -> {
stage.setScene(new Scene(new Region(), 500, 500));
stage.show();
stage.toBack();
stage.toFront();
});
}
@After
public void cleanup() throws Exception {
Platform.runLater(() -> {});
Platform.runLater(() -> {});
Platform.runLater(() -> {});
Platform.runLater(() -> {});
Platform.runLater(() -> {});
setupStage((stage) -> {
stage.close();
});
}
@Test
public void should_call_After_once() {}
@Test
public void should_call_After_twice() {}
@Test
public void should_call_After_thrice() {}
} package org.testfx.cases.bug;
import org.junit.BeforeClass;
import org.testfx.api.FxRobot;
import org.testfx.api.FxToolkit;
public class FxRobotTestBase extends FxRobot {
@BeforeClass
public static void setupSpec() throws Exception {
FxToolkit.registerPrimaryStage();
}
} |
Here are some lines printed out from
The last line (acquire before) was printed after a longer pause. |
I'm a little bit confused by your workaround. You're calling WaitForAsyncUtils#waitForFxEvents() and then calling FxToolkit#setUpStage()? Why not the other way around? Or why not surround setUpStage() with "waitForFxEvents()? Unless the point is to try to short-circuit the deadlock by making sure everything has stopped happening by the time we get there. But then that raises the question of how do I know that Stage is closed when it moves on to the next test? |
|
Oh I see now. I was a little bit confused because none of my tests require |
So then, forgive me if this sounds really stupid, in a typical use case, would I call |
Update: I could minimize the case more. The deadlock could also be reproduced with |
This works. However it does not wait for the @After
public void cleanup() throws Exception {
Platform.runLater(() -> {});
Platform.runLater(() -> {});
Platform.runLater(() -> {});
Platform.runLater(() -> {});
Platform.runLater(() -> {});
Platform.runLater(() -> FxToolkit.toolkitContext().getTargetStage().close());
} |
I'll postpone further investigations to tomorrow or the day after tomorrow. This is not really a blocker for TestFX 4.0.0-beta.1, but it would be nice to have this solved soon. |
Ohhh so if I'm just configuring stuff (Creating, And yeah, Take it at your own pace; for now I can run the tests independently and it all works so this isn't critical for me at all. |
Most probably. The |
Sounds like the end result will be much cleaner than in 3.0 :) |
So I tried implementing a
I called |
Hey. I experimented a bit and called |
Hmm. In case you've never I ran this and it sometimes gave me @After
public void cleanup() throws Exception {
FxToolkit.setupStage((stage) -> stage.close());
PlatformImpl.runAndWait(() -> {});
} The solution was to disable the implicit exit with @After
public void cleanup() throws Exception {
Platform.setImplicitExit(false);
FxToolkit.setupStage((stage) -> stage.close());
} |
Funny thing is, that |
Great! So
Absolutely works (Edit: but wow you were not kidding about reliability). My tests run end to end now after I made one small adjustment. In one of my tests'
This may be an unavoidable aspect of JavaFX, but I would expect the stage in each test to be a new stage ready to be initialized. I could be wrong with that expectation though. I haven't run into the |
This is possible and should be documented as the second of two basic use cases for
I'll see what I can do. |
Hm, okay, I'll play around with those design patterns. I might be doing some things pretty sloppy. The |
Closing due to inactivity. |
Just dropping some info here. I ran into this issue recently, here's a thread dump of what was stuck:
The tests would get stuck when running in The one change I noticed caused the tests to get unstuck (might just be a read herring) was: Not Stuck @Start
void onStart(Stage testStage) throws Exception {
testStage.setScene(new Scene(new GridPane(), 400, 400));
testStage.show();
} Stuck @Start
void onStart(Stage testStage) throws Exception {
testStage.show();
} Hopefully that can guide whoever lands on this sometime in the future. |
Create two test classes, A and B; ensure class A always runs first. Both of these test classes succeed when independently.
In class A, in BeforeClass register the primary stage, create a target stage. Then I setUp the stage, and then I wait for FX events. Like so:
Then I test the stage name and all is good.
In class B, in Before I register the primary stage, then I setUp the stage, then I setUp the scene root, then wait for FX events. getRootNode returns a simple anchorPane with a grid with a button and a comboBox.
Then my tests test the button and the combo box. They run into NPEs attempting to find the nodes:
Here's where things get interesting: I tried to add an AfterClass method to class A that used WaitForAsyncUtils.asyncFx(() to find and close the stage I had set. This time when I ran the tests, class B hung on both setupStage() and setupSceneRoot(); I tried to alter the order.
It looks like some stale data is being left around in FxToolkit, but that's a wildly uninformed guess.
The text was updated successfully, but these errors were encountered: