当前位置: 首页 > 知识库问答 >
问题:

如何用mockito测试正在运行异步线程的方法

丁翊歌
2023-03-14

我有以下代码要测试:

@Slf4j
@Component
public class DispatcherTask {

    private final MyClassService myClassService;
    private final SreamingService streamingService;
    private ExecutorService executor = Executors.newCachedThreadPool();
    private final Set < String > dispatching = new ConcurrentSkipListSet < > ();
    private final RetryPolicy < Object > httpRetryPolicy;

    public DispatcherTask(MyClassService myClassService, SreamingService streamingService) {
        this.myClassService = myClassService;
        this.streamingService = streamingService;
        this.httpRetryPolicy = new RetryPolicy < > ()
            .handle(HttpClientErrorException.class)
            .onRetriesExceeded(e - > log.warn("Max retries have been exceeded for http exception"))
            .withBackoff(2, 3, ChronoUnit.SECONDS)
            .withMaxRetries(5);
    }

    public void initMethod(MyClass myclass) {
        Failsafe.with(httpRetryPolicy).with(executor)
            .onFailure((e) - > {
                // TODO log.error();
                myClassService.updateStatus(myclass.getId(), Status.FAILED);
            })
            .onSuccess((o) - > {
                MyClass updatedMyClass = myClassService.updateStatus(myclass.getId(), GameStatus.ENDED);
                streamingService.storeData(updateMyClass);
                dispatching.remove(myclass.getPlatformId());
                //TODO log.info()
            })
            .runAsync(() - > {
                MyClass updatedMyClass =
                myClassService.updateStatus(myclass.getId(), Status.STREAMING);
                streamingService.polling(StreamedClass.builder().myclass(updatedMyClass).build());
                // TODO log.info()
            });
    }
}

这是我使用mockito进行的JUnit测试:

@ExtendWith(MockitoExtension.class)
public class DispatcherTaskTest {

    @Mock private MyClassService myClassService;
    @Mock private StreamingService streamingService;
    @InjectMocks private DispatcherTask dispatcherTask;

    @Test
    void test() throws InterruptedException {
        //given
        MyClass myclass = new MyClass().setId(1L).setName("name").setStatus(Status.CREATED);
        when(myClassService.updateStatus(myclass.getId(), Status.STREAMING)).thenReturn(myclass);
        when(myClassService.updateStatus(myclass.getId(), Status.ENDED)).thenReturn(myclass);
        doNothing().when(streamingService).polling(any());
        doNothing().when(streamingService).storeData(any());
        //when
        dispatcherTask.initMethod(myclass)
        //then
        verify(myClassService, times(1)).updateStatus(myclass.getId(), Status.STREAMING);
        verify(myClassService, times(1)).updateStatus(myclass.getId(), Status.ENDED);
    }
}

如果我这样运行它,则检查状态Ended的最后一次验证将失败。如果添加thread.sleep(3L);,它就会通过。是否有更好或更安全的方法通过测试,而不添加sleep()方法?

共有2个答案

暴绪
2023-03-14

您可以在Dispatcher类中添加shutdownawaittermination方法。(如果需要,您可以统一它们)

public class DispatcherTask 
{    
  //...
  public void shutdownExecutor()
  {
     executor.shutdown();
  }
  public void waitToFinish(long seconds)
  {
     executor.awaitTermination(seconds,TimeUnit.SECONDS);
  }
  //...
}

布尔等待终止

阻塞,直到在关闭请求后所有任务都已完成执行,或发生超时,或当前线程中断(以先发生者为准)。

在Dispatcher中使用此方法,可以更改测试,以便您可以:

@Test
void test() throws InterruptedException {
    //...
    dispatcherTask.initMethod(myclass);
    verify(myClassService, times(1)).updateStatus(myclass.getId(), Status.STREAMING);
   
    dispatcherTask.shutdownExecutor();
    dispatcherTask.waitToFinish(3L); //this will block without manually sleeping
    verify(myClassService, times(1)).updateStatus(myclass.getId(), Status.ENDED);
}
顾文昌
2023-03-14

我甚至不尝试在单元测试中管理其他线程。我不确定示例中的executor从何而来,但我会在测试中注入一个在当前线程上执行的版本。Guava从com.google.common.util.concurrent.MoreExecutors::DirectExecutor返回一个。

 类似资料:
  • 问题内容: 我有一个正在运行的线程,但是从外面我无法绕过一个值来停止该线程。如何在内部发送false / true值或调用运行线程的公共方法?当我按下按钮1?例如: 或 跟进(校对): 问题答案: 如果您通过类而不是通过a定义它,则可以调用实例方法。 还要注意,由于多个内核具有自己的关联内存,因此您需要警告处理器该状态可能在另一个处理器上更改,并且它需要监视该更改。听起来很复杂,但只需将’vola

  • 我正在尝试运行一个使用Mockito的JUnit cucumber测试。这是我遇到的问题。在我的cucumber赛跑课上,我有 在我的常规JUnit测试中 鉴于我一次只能有一个@RunWith,我如何将Mockito与cucumber结合使用呢?

  • 我有一个函数,在这个函数中,我想替换一些组件的行为(余弦,正弦,...),我正在尝试为这些部分创建一个mock,并将它们传递给函数。 问题是,我收到以下消息: *org.mockito.exceptions.misusing.MissingMethodInvocationException:当()需要一个必须是“模拟上的方法调用”的参数。例如:当(mock.getArticles()). then

  • 问题内容: 您如何测试使用JUnit触发异步流程的方法? 我不知道如何让我的测试等待过程结束(这不完全是单元测试,它更像是集成测试,因为它涉及多个类,而不仅仅是一个类)。 问题答案: 恕我直言,让单元测试创​​建或在线程上等待是不好的做法。您希望这些测试能在几秒钟内运行。这就是为什么我想提出一种分两步的方法来测试异步过程。 测试您的异步过程是否已正确提交。您可以模拟接受异步请求的对象,并确保提交的

  • 问题内容: 我已经开始发现Mockito库,并且有一个我没有找到正确答案的问题。 例如,如果我的UserDAO类中有将用户保存到数据库中的此类方法: 我应该如何测试? 如果我想测试一个DAO类,那么我需要创建一个模拟,模拟,模拟等吗?如此不测试数据库本身? 但是,如果我还想测试dao和数据库的行为怎么办? 您能否提供一些代码示例,可能有用的链接,并显示实现此目的的最佳方法? 问题答案: 这是使用M

  • 问题内容: 我有一个需要执行两项操作的功能,一项功能完成得很快,而一项则需要很长时间才能运行。我希望能够将长时间运行的操作委派给线程,并且我不在乎线程何时完成,但是线程需要完成。我实现了如下所示的方法,但是由于函数在start()调用后退出,因此我的第二个操作从未完成。如何确保函数返回但第二个操作线程也完成其执行并且不依赖于父线程? 问题答案: 如果调用了if ,则JVM将运行if 运行它的线程未