【问题标题】:Testing threaded lambda function in spring controller在弹簧控制器中测试线程 lambda 函数
【发布时间】:2018-06-19 15:04:47
【问题描述】:

我在控制器中有一个简单的端点,因为它是:

private final ExecutorService threadPoolExecutor = Executors.newFixedThreadPool(6);
@PostMapping(path = "/batch")
public ServiceResponse batch(@RequestBody BatchRequest request) {
    threadPoolExecutor.submit(() -> {
        try {
            service.batch(request);
            log.info("Batch finished");
        } catch (Exception e) {
            log.error("Failed to execute. Cause: ");
            e.printStackTrace();
        }
    });
    return ServiceResponse.asSuccess("Ok");
}

这样做是因为服务可能需要几分钟才能运行,因此我们避免锁定整个系统。我正在尝试对此进行单元测试并捕获它的异常(增加代码覆盖率)。这是我到现在才想到的

@Rule
public ExpectedException exception = ExpectedException.none();

@InjectMocks
private MyController controller;

@MockBean
private MyService service;

@Test
public void testBatchThrowsException() throws Exception {
    createRequest();

    when(service.batch(any())).thenThrow(Exception.class);


    mockMvc.perform(post(Controller.URL_PREFIX+"/batch")
            .contentType(MediaType.APPLICATION_JSON)
            .content(request.toString()))
            .andDo(MockMvcResultHandlers.print())
            .andExpect(status().isOk());
    exception.expect(Exception.class);
}

当然它会返回成功,因为请求结束时线程仍在运行。有没有办法模拟执行者并获得结果或类似的东西?我尝试过使用 Awaitility,但无法正确调用 lambda 函数。

【问题讨论】:

    标签: multithreading spring-boot junit mockito


    【解决方案1】:

    为了“返回某些东西”,您唯一能做的就是更改控制器代码的实现(可能使用 Future 或其他东西)。

    但是,如果你做不到,想法可能是在测试用例中延迟主线程,然后检查是否调用了特定方法。

    如果您无法更改实际代码的实现,我的建议是:

    • 在测试类中对控制器的调用下方 - 使用 Thread.sleep 或其他方式延迟主线程
    • 从服务中抛出模拟异常
    • 使用 mockito 验证生产行为:计算异常模拟时 printStackTrace() 的调用次数,计算服务调用次数
    • 可选 - 让测试超时,以确保它持续预期的时间段

    另外,请阅读Waiting for all threads spawned by my code under test in JUnit test case

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-08
      • 1970-01-01
      • 2014-11-30
      • 1970-01-01
      • 1970-01-01
      • 2016-03-28
      • 2014-02-09
      相关资源
      最近更新 更多