【问题标题】:Junit/Mockito - wait for method executionJunit/Mockito - 等待方法执行
【发布时间】:2013-05-19 16:31:49
【问题描述】:

在我的应用程序中,我将观察者模式用于某些操作,并且我想在单元测试中对其进行测试。问题是我不知道如何使用 junit/mockito/其他东西测试观察者。有什么帮助吗?

例如这是我的单元测试:

@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"));
}

我不想使用Thread.sleep(),而是以这种方式(或类似方式)使用它:

@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"));
}

【问题讨论】:

    标签: java android unit-testing junit mockito


    【解决方案1】:

    如果我理解正确的话,问题并不是真正测试观察者,而是测试异步方法调用的结果。为此,请创建一个观察者,该观察者在调用其 update() 方法之前一直阻塞。类似于以下内容:

    public class BlockingGameObserver extends GameInstanceObserver {
        private CountDownLatch latch = new CountDownLatch(1);
    
        @Override
        public void update() {
            latch.countDown();
        }
    
        public void waitUntilUpdateIsCalled() throws InterruptedException {
            latch.await();
        }
    }
    

    在你的测试中:

    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());
    }
    

    【讨论】:

    • 仅供参考,GitHub 中有一个专门为此目的设计的 CountDownLatchAnswer:github.com/dancerjohn/LibEx/blob/master/testlibex/src/main/java/…
    • @JohnB,谢谢。我在哪里可以阅读有关此 LibEx 库的更多信息?如何使用它,创建它的目的等等?
    • 我创建它是为了添加通用功能(通常扩展 Guava,但并非总是如此)。 GitHub 中有一个示例项目,其中包含一些示例,但不是全部。一般来说,提供的 javadocs 是唯一的文档。 wiki 提供了指向 javadocs 的链接:github.com/dancerjohn/LibEx/wiki
    • 这是一个好方法,只要你不做验证。但是,如果在上面的示例中,您还想验证仅在将观察者创建为间谍时才调用观察者的更新方法:observer = spy(new BlockingGameObserver()); 并在assertEquals 之后进行验证:verify(observer).update();。然而,这很容易在并发场景中中断,因为在 Mockito 在间谍上注册对 update 方法的调用之前锁存器已关闭,而后者在我们到达验证调用时可能不会发生。有人知道如何安全地进行此类测试吗?
    猜你喜欢
    • 2020-04-17
    • 2018-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多