首页 > 解决方案 > Junit 模拟异步线程调用

问题描述

我正在尝试对 A 类进行单元测试,其中 A 类如下

Class A{
private final classB = new ClassB();


public Void test(ScheduledEvent scheduledEvent, Context context) {


        try {
            Thread thread2 = new Thread(() -> doHandleRequest());
            thread2.start();
            thread2.join(3000);
            if (thread2.isAlive()) {
                thread2.interrupt();
                // sleep for 30 seconds to flush any logs or CFN metrics.
                Thread.sleep(30000);
            }
        } catch (InterruptedException ex) {

        }
    }
    void doHandleRequest() {

        try {
            classB.sweep();
        } catch(Exception ex) {
            log.error("Exception in SweepThread while sweeping and deleting lambdas", ex);
        }
    }
}

Class B{
 public void sweep(){
// do something;
}

我想对 thread2.isAlive() 条件为真并且进入 if 块的 A 类场景进行单元测试。

标签: javaasynchronousjunitjunit5

解决方案


首先,您需要更改创建ClassB对象的方式以允许模拟,每次都创建对象时无法做到这一点。

你可以这样做

public class ClassA {
   private final ClassB b;

   // this will allow you to inject mock from outside, as it's final, can be initialized only via a constructor.

   public ClassA(ClassB b){
      this.b = b;
   }

  // your remaining code

} 

现在,在您的测试用例中,您需要注入模拟。

@Test
public void test() throws InterruptedException {
    ClassB classB = Mockito.mock(ClassB.class);
    ClassA classA = new ClassA(classB);

    MockitoAnnotations.initMocks(this);  // this will initialize mocks

    //above can be skipped if you are using annotations for the same


    Mockito.stubVoid(classB)
      .toAnswer(invocationOnMock -> {
        Thread.sleep(4000);
        return null;
      }).on().sweeps();

    parent.test(null, null);
}

为确保您的线程在 之后是活动的join,您可以在 的模拟方法中添加延迟classB

由于你的方法返回void,我们需要使用stubVoid,否则会是这样。

Mockito.when(mock.method(/* args, if, any */)).thenAnswer(mock -> {
   Thread.sleep(delayInMilliseconds);
   return desiredValue;
})

推荐阅读