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());
}
Share:
10,029
pepuch
Author by

pepuch

Updated on June 12, 2022

Comments

  • pepuch
    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
    John B almost 11 years
    FYI, there is a CountDownLatchAnswer checked into GitHub that is designed for this purpose: github.com/dancerjohn/LibEx/blob/master/testlibex/src/main/j‌​ava/…
  • pepuch
    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
    John B almost 11 years
    I 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
    Mikha about 10 years
    this 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 after assertEquals 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?