-
Notifications
You must be signed in to change notification settings - Fork 104
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #266 from sialcasa/263_publish_testable
#263 publish testable
- Loading branch information
Showing
5 changed files
with
258 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
138 changes: 138 additions & 0 deletions
138
mvvmfx/src/main/java/de/saxsys/mvvmfx/utils/notifications/NotificationTestHelper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
package de.saxsys.mvvmfx.utils.notifications; | ||
|
||
import de.saxsys.mvvmfx.ViewModel; | ||
import javafx.application.Platform; | ||
import javafx.embed.swing.JFXPanel; | ||
import javafx.util.Pair; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.concurrent.CompletableFuture; | ||
import java.util.concurrent.ExecutionException; | ||
import java.util.concurrent.TimeUnit; | ||
import java.util.concurrent.TimeoutException; | ||
|
||
/** | ||
* The {@link NotificationTestHelper} is used to simplify the testing of | ||
* notifications. It is especially useful when notifications are send from | ||
* different thread and when testing the direct notification between a viewModel and the View | ||
* (via {@link ViewModel#publish(String, Object...)} and {@link ViewModel#subscribe(String, NotificationObserver)}) | ||
* <p> | ||
* This class implements {@link NotificationObserver} and therefore can be added as subscriber. It will record | ||
* every received notification and can be tested afterwards. | ||
* <p> | ||
* | ||
* The {@link ViewModel#publish(String, Object...)} method will send all notifications on the JavaFX UI thread. | ||
* Therefore when testing the publishing of notifications JavaFX has to be running which isn't the case | ||
* with plain JUnit tests. The {@link NotificationTestHelper} will take care for thread handling. | ||
* | ||
* <p> | ||
* Example: | ||
* <p> | ||
* | ||
* <pre> | ||
* | ||
* public class MyViewModel implements ViewModel { | ||
* public static final String ACTION_KEY = "my-action"; | ||
* | ||
* public void someAction() { | ||
* ... | ||
* publish(ACTION_KEY); | ||
* } | ||
* } | ||
* | ||
* // unit test | ||
* {@code @Test} | ||
* public void testSomething() { | ||
* MyViewModel viewModel = new MyViewModel(); | ||
* | ||
* NotificationTestHelper helper = new NotificationTestHelper(); | ||
* viewModel.subscribe(MyViewModel.ACTION_KEY, helper); | ||
* | ||
* | ||
* viewModel.someAction(); | ||
* | ||
* assertEquals(1, helper.numberOfReceivedNotifications()); | ||
* } | ||
* </pre> | ||
* | ||
* | ||
* | ||
* You can provide a timeout as constructor parameter. | ||
* This is useful in case of asynchronous code (f.e. when notifications are send from another Thread). | ||
* | ||
* By default the timeout is set to {@value #DEFAULT_TIMEOUT}. When you have a long running thread | ||
* you should use a higher timeout. | ||
* | ||
* @author manuel.mauky | ||
*/ | ||
public class NotificationTestHelper implements NotificationObserver { | ||
|
||
public static final long DEFAULT_TIMEOUT = 0l; | ||
|
||
private List<Pair<String, Object[]>> notifications = new ArrayList<>(); | ||
|
||
private long timeout = DEFAULT_TIMEOUT; | ||
|
||
/** | ||
* Create a test helper with a default timeout of {@value #DEFAULT_TIMEOUT} millis. | ||
*/ | ||
public NotificationTestHelper() { | ||
new JFXPanel(); | ||
} | ||
|
||
/** | ||
* Create a test helper with the given timeout in millis. | ||
* | ||
* @param timeoutInMillis the timeout. | ||
*/ | ||
public NotificationTestHelper(long timeoutInMillis) { | ||
this(); | ||
this.timeout = timeoutInMillis; | ||
} | ||
|
||
@Override | ||
public void receivedNotification(String key, Object... payload) { | ||
notifications.add(new Pair<>(key, payload)); | ||
} | ||
|
||
/** | ||
* @return the number of received notifications. | ||
*/ | ||
public int numberOfReceivedNotifications() { | ||
waitForUiThread(); | ||
return notifications.size(); | ||
} | ||
|
||
/** | ||
* @param key the key of the notification. | ||
* @return the number of received notifications for the given key. | ||
*/ | ||
public int numberOfReceivedNotifications(String key) { | ||
waitForUiThread(); | ||
return (int) notifications.stream() | ||
.filter(pair -> pair.getKey().equals(key)) | ||
.count(); | ||
} | ||
|
||
private void waitForUiThread() { | ||
CompletableFuture<Void> future = new CompletableFuture<>(); | ||
|
||
Platform.runLater(() -> { | ||
if(timeout > 0) { | ||
try { | ||
Thread.sleep(timeout); | ||
} catch (InterruptedException e) { | ||
e.printStackTrace(); | ||
} | ||
} | ||
future.complete(null); | ||
}); | ||
|
||
try { | ||
future.get(timeout+50, TimeUnit.MILLISECONDS); | ||
} catch (InterruptedException | ExecutionException | TimeoutException e) { | ||
e.printStackTrace(); | ||
} | ||
} | ||
} |
101 changes: 101 additions & 0 deletions
101
mvvmfx/src/test/java/de/saxsys/mvvmfx/utils/notifications/NotificationTestHelperTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package de.saxsys.mvvmfx.utils.notifications; | ||
|
||
import static org.assertj.core.api.Assertions.*; | ||
|
||
import org.junit.Before; | ||
import org.junit.Test; | ||
|
||
import de.saxsys.mvvmfx.ViewModel; | ||
|
||
/** | ||
* @author manuel.mauky | ||
*/ | ||
public class NotificationTestHelperTest { | ||
|
||
public class MyViewModel implements ViewModel { | ||
} | ||
|
||
private MyViewModel viewModel; | ||
|
||
@Before | ||
public void setUp() throws Exception { | ||
viewModel = new MyViewModel(); | ||
} | ||
@Test | ||
public void singlePublish () { | ||
NotificationTestHelper helper = new NotificationTestHelper(); | ||
viewModel.subscribe("test", helper); | ||
|
||
viewModel.publish("test"); | ||
|
||
assertThat(helper.numberOfReceivedNotifications()).isEqualTo(1); | ||
} | ||
|
||
@Test | ||
public void multiplePublish() { | ||
NotificationTestHelper helper = new NotificationTestHelper(); | ||
viewModel.subscribe("test", helper); | ||
|
||
int n = 10; | ||
|
||
for(int i=0 ; i<n; i++) { | ||
viewModel.publish("test"); | ||
} | ||
|
||
assertThat(helper.numberOfReceivedNotifications()).isEqualTo(n); | ||
} | ||
|
||
@Test | ||
public void globalNotificationCenter() { | ||
NotificationTestHelper helper = new NotificationTestHelper(); | ||
|
||
NotificationCenter notificationCenter = new DefaultNotificationCenter(); | ||
|
||
notificationCenter.subscribe("OK", helper); | ||
|
||
|
||
notificationCenter.publish("OK"); | ||
|
||
|
||
assertThat(helper.numberOfReceivedNotifications()).isEqualTo(1); | ||
} | ||
|
||
@Test | ||
public void publishOnOtherThread(){ | ||
NotificationTestHelper helper = new NotificationTestHelper(50l); | ||
|
||
NotificationCenter notificationCenter = new DefaultNotificationCenter(); | ||
|
||
notificationCenter.subscribe("OK", helper); | ||
|
||
|
||
Runnable r = () -> notificationCenter.publish("OK"); | ||
|
||
new Thread(r).start(); | ||
|
||
assertThat(helper.numberOfReceivedNotifications()).isEqualTo(1); | ||
} | ||
|
||
@Test | ||
public void timeout() { | ||
NotificationTestHelper helper = new NotificationTestHelper(150l); | ||
|
||
NotificationCenter notificationCenter = new DefaultNotificationCenter(); | ||
|
||
notificationCenter.subscribe("OK", helper); | ||
|
||
|
||
Runnable r = () -> { | ||
try { | ||
Thread.sleep(100l); | ||
} catch (InterruptedException e) { | ||
e.printStackTrace(); | ||
} | ||
notificationCenter.publish("OK"); | ||
}; | ||
|
||
new Thread(r).start(); | ||
|
||
assertThat(helper.numberOfReceivedNotifications()).isEqualTo(1); | ||
} | ||
} |