Junit/Mockito - wait for method execution
10,029
If I understand correctly, the problem is not really to test the observer, but to test the result of an asynchronous method call. To do that, create an observer which blocks until its update() method has been called. Something like the following:
public class BlockingGameObserver extends GameInstanceObserver {
private CountDownLatch latch = new CountDownLatch(1);
@Override
public void update() {
latch.countDown();
}
public void waitUntilUpdateIsCalled() throws InterruptedException {
latch.await();
}
}
And in your test:
private BlockingGameObserver observer;
@Before
public void setUp() throws IOException, Exception {
observer = new BlockingGameObserver();
GameInstance.getInstance().addObserver(observer);
}
@Test
public void getRoomUserData_usingNullKey_shouldThrowUserDataDoesntExist() throws InterruptedException, UserDataDoesntExistException {
serverService.createRoom("exampleRoom");
observer.waitUntilUpdateIsCalled();
assertEquals("exampleRoom",
GameInstance.getInstance().getRoom("exampleRoom").getRoomId());
}
Author by
pepuch
Updated on June 12, 2022Comments
-
pepuch almost 2 years
In my application I use observer pattern for some operations and I want to test them in unit tests. The problem is that I don't know how can I test observers using junit/mockito/something else. Any help?
For example this is my unit test:
@Before public void setUp() throws IOException, Exception { observer = new GameInstanceObserver(); // observable (GameInstance) will call update() method after every change GameInstance.getInstance().addObserver(observer); // this is observable which is updated by serverService } @Test(expected = UserDataDoesntExistException.class) public void getRoomUserData_usingNullKey_shouldThrowUserDataDoesntExist() throws InterruptedException, UserDataDoesntExistException { serverService.createRoom("exampleRoom"); // this operation is asynchronous and updates GameInstance data (as I wrote before GameInstance is Observable) Thread.sleep(400); // how to do it in better way? GameInstance gi = (GameInstance) observer.getObservable(); assertTrue(gi.getRoom("exampleRoom").getRoomId().equals("exampleRoom")); }
I would like to not use
Thread.sleep()
and use it in that way (or similar):@Test(expected = UserDataDoesntExistException.class) public void getRoomUserData_usingNullKey_shouldThrowUserDataDoesntExist() throws InterruptedException, UserDataDoesntExistException { serverService.createRoom("exampleRoom"); // this operation is asynchronous and updates GameInstance data (as I wrote before GameInstance is Observable) waitUntilDataChange(GameInstance.getInstance()); // wait until observable will be changed so I know that it notified all observer and I can validate data GameInstance gi = (GameInstance) observer.getObservable(); assertTrue(gi.getRoom("exampleRoom").getRoomId().equals("exampleRoom")); }
-
John B almost 11 yearsFYI, there is a CountDownLatchAnswer checked into GitHub that is designed for this purpose: github.com/dancerjohn/LibEx/blob/master/testlibex/src/main/java/…
-
pepuch almost 11 years@JohnB, thanks. Where can I read more information about this LibEx library? How to use it, what for it was created and so on?
-
John B almost 11 yearsI created it as a place to add common functionality (usually extending Guava but not always). There is an examples project in GitHub that has SOME examples but not all. In general the javadocs provided are the only documentation. The wiki provides links to the javadocs: github.com/dancerjohn/LibEx/wiki
-
Mikha about 10 yearsthis is a good approach as long as you don't do verification. however if in the example above you also want to verify that update method on the observer is called only once you would create observer as a spy:
observer = spy(new BlockingGameObserver());
and afterassertEquals
do the verification:verify(observer).update();
. however this easily breaks in concurrent scenario since latch gets down before Mockito registers the call to update method on the spy and the latter might not happen by the time we reach verify call. does anyone have any idea how to do such test safely?