没有Thread.sleep的异步测试

时间:2016-07-20 13:01:59

标签: java testing asynchronous callback integration-testing

目前,我想验证SUT(被测系统)是否正确地向外部系统发送请求。我在QA环境中使用外部模拟(通过HTTP)和消息队列(它们可以通过配置由真实系统交换)。

问题:要对这些外部系统进行断言,我正在<?php session_start(); $id = $_GET['id']; if(isset($_SESSION[$id])){ echo "working"; }else{ echo "not working"; } ?> 进行集成测试,这很糟糕。我想用一个带有回调的请求和一个为这些请求提供监听器的测试套件来替换它。是否已有解决方案?

1 个答案:

答案 0 :(得分:1)

对于您描述的场景,我可以建议使用类java.util.concurrent.CyclicBarrier的实例 - 请参阅以下简单示例,该线程以异步方式执行某些计算(此处简化为首先将“完成百分比”值设置为50然后再到100)并允许从主线程中检索“完成百分比”值。

这是SUT类:

public class AsyncProcess implements Runnable {

  private int percentageDone = 0;

  public int getPercentageDone() { return percentageDone; }

  public void doFirstHalf() { percentageDone = 50; }

  public void doSecondHalf() { percentageDone = 100; }

  public void run() {
    doFirstHalf();
    doSecondHalf();
  }

}

对于单元测试,我使用JUnit 4,与Mockito间谍拦截我的SUT的两种计算方法(或者,你可以使用你最喜欢的AOP框架)。

import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.doAnswer;

import java.util.concurrent.CyclicBarrier;

import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

public class AsyncProcessTest {

  @Test
  public void testExecute() throws Exception {

    final CyclicBarrier firstHalfStarted = new CyclicBarrier(2);
    final CyclicBarrier firstHalfFinished = new CyclicBarrier(2);
    final CyclicBarrier secondHalfStarted = new CyclicBarrier(2);
    final CyclicBarrier secondHalfFinished = new CyclicBarrier(2);

    AsyncProcess process = Mockito.spy(new AsyncProcess());

    doAnswer(new Answer() {
      public Object answer(InvocationOnMock invocation) throws Throwable {
        firstHalfStarted.await();
        invocation.callRealMethod();
        firstHalfFinished.await();
        return null;
      }
    }).when(process).doFirstHalf();

    doAnswer(new Answer() {
      public Object answer(InvocationOnMock invocation) throws Throwable {
        secondHalfStarted.await();
        invocation.callRealMethod();
        secondHalfFinished.await();
        return null;
      }
    }).when(process).doSecondHalf();

    new Thread(process, "AsyncProcess").start();

    assertThat(process.getPercentageDone(), is(0));

    firstHalfStarted.await();
    firstHalfFinished.await();

    assertThat(process.getPercentageDone(), is(50));

    secondHalfStarted.await();
    secondHalfFinished.await();

    assertThat(process.getPercentageDone(), is(100));
  }

}

这种方法允许对所涉及的线程的执行流程进行非常精细的控制。通过封装CyclicBarriers对并提取拦截调用以及支持超时和正确的异常处理,它可以很容易地扩展到“微框架”。