【问题标题】:Testing an async method call测试异步方法调用
【发布时间】:2011-09-29 08:17:43
【问题描述】:

以下是我的应用程序的简化设置。它有一个类 Foobar,它调用一个外观方法来获取数据。然后,facade 调用一个 web 服务来实际获取数据,然后对数据进行一点操作,然后将其返回给 Foobar。

现在因为 Web 服务可能需要很长时间才能运行,所以对外观的方法调用需要是异步的。因此,外观的方法没有返回值,而是使用回调对象。查看示例并继续阅读下面的内容。

public class Foobar {
    private List<DTO> dtos;

    @Autowired
    private Facade facade;

    public void refresh() {
        facade.refreshFoobar(new CallBack() {
            public void dataFetched(List<DTO> dtos) {
                setDtos(dtos);
            }

        });
    }    

    public void setDtos(List<DTO> dtos) {
        this.dtos = dtos;
    }
}


public class Facade {

    ...

    public void refreshFoorbar(CallBack cb) {
        // Fetch data from a web service
        List<DTO> dtos = webService.getData();  
        // Manipulate DTOs
        ....
        // call on the callback method
        cb.dataFecthed(dtos);
    }

}

我有两种方法可以使外观的方法异步,要么手动创建线程,要么使用 springs @Async 注解。

public class Facade {

    public void refreshFoorbar(CallBack cb) {
        new Thread() {

            @Override
            public void run() {
                ....
            }

        }.start();

    }
}

// ... OR ...

public class Facade {

    @Async
    public void refreshFoorbar(CallBack cb) {
        ....    
    }
}

我的问题是我现在需要为这个方法调用链编写一个集成测试。我想我需要在运行集成测试时强制异步外观调用是同步的,否则我无法确定何时可以进行适当的断言。使方法调用同步的唯一想法是使用手动处理的线程并使线程有条件(因此,出于测试目的,我有一个 if 子句来确定是否应该在单独的线程中运行外观方法)。

但是,我觉得可能有更好的解决方案来解决我的问题,无论是强制方法同步给我的更好方法,例如使用 spring,还是通过以某种方式测试多线程。

这是我需要您的建议的地方,您将如何解决我的问题?请注意,我将 junit 用于单元测试和集成测试。

【问题讨论】:

  • 不知道这样是否正确。通常测试异步条件只是启动异步任务,稍等片刻,测试任务是否完成。

标签: java testing junit integration-testing


【解决方案1】:

简单的解决方案是像这样返回一个 Future 对象,

@Async
public Future<String> refreshFoorbar(CallBack cb) {
    yourHeavyLifting(); //asynchronous call
    return new AsyncResult<String>("yourJobNameMaybe");   
}

在您的测试中,获取将来的引用并调用get() 方法。

future.get(); // if its not already complete, waits for it to complete
assertTrue(yourTestCondition)

blog post 显示了一个示例。

【讨论】:

【解决方案2】:

当 JUnit 测试这样的东西时,我使用带有 CountDownLatch 的测试回调,该回调由回调倒计时,await() 由测试方法生成。

private static class TestingCallback implements Callback {
    private final CountDownLatch latch;
    public TestingCallback(CountDownLatch latch) {
        this.latch = latch;
    }
    @Override public void onEvent() {
        this.latch.countDown();
    }
}

@Test
public void testCallback() {
    final CountDownLatch latch = new CountDownLatch(1);

    classUnderTest.execute( new TestCallback(latch) );

    assertTrue(latch.await(30, TimeUnit.SECONDS));
}

如果被测试代码(异步)调用回调,则锁存器返回true,测试通过。如果回调没有被调用,三十秒后测试超时并且断言失败。

【讨论】:

    猜你喜欢
    • 2017-12-21
    • 2014-02-14
    • 1970-01-01
    • 2021-06-08
    • 2015-02-13
    • 2020-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多