当前位置:  开发笔记 > 编程语言 > 正文

如何使用Junit测试异步进程

如何解决《如何使用Junit测试异步进程》经验,为你挑选了7个好方法。

如何测试使用Junit激发异步进程的方法?

我不知道如何让我的测试等待进程结束(它不是一个单元测试,它更像是一个集成测试,因为它涉及几个类而不仅仅是一个)



1> Martin..:

另一种方法是使用CountDownLatch类.

public class DatabaseTest {

    /**
     * Data limit
     */
    private static final int DATA_LIMIT = 5;

    /**
     * Countdown latch
     */
    private CountDownLatch lock = new CountDownLatch(1);

    /**
     * Received data
     */
    private List receiveddata;

    @Test
    public void testDataRetrieval() throws Exception {
        Database db = new MockDatabaseImpl();
        db.getData(DATA_LIMIT, new DataCallback() {
            @Override
            public void onSuccess(List data) {
                receiveddata = data;
                lock.countDown();
            }
        });

        lock.await(2000, TimeUnit.MILLISECONDS);

        assertNotNull(receiveddata);
        assertEquals(DATA_LIMIT, receiveddata.size());
    }
}

注意你不能只使用与常规对象同步作为锁,因为快速回调可以在调用lock的wait方法之前释放锁.请参阅Joe Walnes撰写的这篇博客文章.

EDIT删除了CountDownLatch周围的同步块,感谢@jtahlborn和@Ring的评论


请不要按照这个例子,这是不正确的.你应该__ __在CountDownLatch上同步,因为它在内部处理线程安全.
如果您正在验证是否已调用onSuccess,则应断言lock.await返回true.
为错误道歉.我已经适当地编辑了答案.

2> Johan..:

您可以尝试使用Awaitility库.它可以轻松测试您正在谈论的系统.


友好的免责声明:约翰是该项目的主要贡献者.

3> user393274..:

如果您使用CompletableFuture(在Java 8中引入)或SettableFuture(来自Google Guava),您可以在完成后立即完成测试,而不是等待预先设定的时间.您的测试看起来像这样:

CompletableFuture future = new CompletableFuture<>();
executorService.submit(new Runnable() {         
    @Override
    public void run() {
        future.complete("Hello World!");                
    }
});
assertEquals("Hello World!", future.get());


...如果你遇到java-less-than-eight try guavas [SettableFuture](http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/util/concurrent /SettableFuture.html)它做了几乎相同的事情

4> Cem Catikkas..:

恕我直言,让单元测试创​​建或等待线程等是不好的做法.你希望这些测试在几秒钟内运行.这就是为什么我想提出一个两步测试异步过程的方法.

    测试您的异步过程是否正确提交.您可以模拟接受异步请求的对象,并确保提交的作业具有正确的属性等.

    测试你的异步回调正在做正确的事情.在这里,您可以模拟最初提交的作业并假设它已正确初始化并验证您的回调是否正确.


当然.但有时您需要测试专门用于管理线程的代码.
对于我们这些使用Junit或TestNG进行集成测试(而不仅仅是单元测试)或用户验收测试(例如w/Cucumber)的人来说,等待异步完成并验证结果是绝对必要的.
异步进程是一些最复杂的代码,你说你不应该对它们使用单​​元测试,只用单个线程进行测试?这是一个非常糟糕的主意.
模拟测试通常无法证明功能是端到端的.异步功能需要以异步方式进行测试,以确保其正常工作.如果您愿意,可以将其称为集成测试,但这仍然是需要的测试.
这个答案以单元测试的角度给出.
这不应该是公认的答案.测试不仅仅是单元测试.OP将其称为集成测试而不是单元测试.

5> Tom Hawtin -..:

关闭该过程并使用a等待结果Future.



6> Matt..:

我发现一种测试异步方法非常有用的方法是Executor在object-to-test的构造函数中注入一个实例.在生产中,执行程序实例配置为异步运行,而在测试中,它可以被模拟为同步运行.

所以假设我正在尝试测试异步方法Foo#doAsync(Callback c),

class Foo {
  private final Executor executor;
  public Foo(Executor executor) {
    this.executor = executor;
  }

  public void doAsync(Callback c) {
    executor.execute(new Runnable() {
      @Override public void run() {
        // Do stuff here
        c.onComplete(data);
      }
    });
  }
}

在生产中,我将Foo使用Executors.newSingleThreadExecutor()Executor实例构建,而在测试中,我可能会使用执行以下操作的同步执行程序构造它 -

class SynchronousExecutor implements Executor {
  @Override public void execute(Runnable r) {
    r.run();
  }
}

现在我对异步方法的JUnit测试很干净 -

@Test public void testDoAsync() {
  Executor executor = new SynchronousExecutor();
  Foo objectToTest = new Foo(executor);

  Callback callback = mock(Callback.class);
  objectToTest.doAsync(callback);

  // Verify that Callback#onComplete was called using Mockito.
  verify(callback).onComplete(any(Data.class));

  // Assert that we got back the data that we expected.
  assertEquals(expectedData, callback.getData());
}



7> Jonathan..:

测试线程/异步代码没有任何内在错误,特别是如果线程是您正在测试的代码的重点.测试这些东西的一般方法是:

阻止主测试线程

从其他线程捕获失败的断言

取消阻止主测试线程

重新抛出任何失败

但这是一次测试的很多样板.更好/更简单的方法是使用ConcurrentUnit:

  final Waiter waiter = new Waiter();

  new Thread(() -> {
    doSomeWork();
    waiter.assertTrue(true);
    waiter.resume();
  }).start();

  // Wait for resume() to be called
  waiter.await(1000);

这种CountdownLatch方法的好处在于,它更简洁,因为任何线程中发生的断言失败都被正确地报告给主线程,这意味着测试失败了.这里比较了CountdownLatchConcurrentUnit 的方法.

我还为那些想要学习更多细节的人写了一篇关于这个主题的博客文章.

推荐阅读
mobiledu2402851323
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有