java - 使用 EasyMock 或 Mockito 模拟 void 方法的 try catch block 并捕获异常

标签 java junit mocking mockito easymock

我有一个类似这样的代码,我想完全为下面的代码编写一个单元测试。我能够尝试部分代码,但无法弄清楚如何测试捕获异常部分。

public class CacheUpdateTask implements Runnable {

    private WarehouseCache cache;

    private static final int EXPONENTIAL_MULTIPLIER = 100;

    private static final int MAXIMUM_TIME_LIMIT = 5;

    public CacheUpdateTask(
            final WarehouseCache cache) {
        this.cache = cache;
    }

    @Override
    public void run() {
        LOG.info("Requesting warehouse mapping from AService and updating the cache.");
        final Callable<Void> updateCache =
                new Callable<Void>() {
                    @Override
                    public Void call() throws Exception {
                        cache.updateWarehouseCountryCodeCache();
                        return null;
                    }
                };
        final Retryer<Void> retryer = RetryerBuilder.<Void>newBuilder()
                .retryIfException()
                .withWaitStrategy(WaitStrategies.exponentialWait(EXPONENTIAL_MULTIPLIER, MAXIMUM_TIME_LIMIT,
                        TimeUnit.MINUTES))
                .withStopStrategy(StopStrategies.neverStop())
                .build();
        try {
            retryer.call(updateCache); // this is also a void method, so no return here
        } catch (ExecutionException | RetryException e) {
            e.printStackTrace();
            LOG.error(e);
            LOG.error("Exception when refreshing the cache.");
        }
        LOG.info("Cache has been updated.");
    }
}

注意事项

  • 此处重试器配置为 neverStop。每当调用 retryer.call(updateCache); 引发异常时,重试器实际上会重试。因此,在 try block 中,当 retryer.call(updateCache) 抛出异常时,执行不会流向 catch block ,而是继续尝试。
  • 我尝试模仿try block 中的代码以多种方式抛出一些异常,但它从未调用catch中的代码。下面的代码是我在创建这个问题之前的最后一次尝试。在我的大多数尝试中,测试都成功,但我永远不会结束测试 catch block
  • 下面的代码运行成功,但根据代码覆盖率测试,它实际上没有命中 catch block
@Test (expected = ExecutionException.class)
    public void test_UpdateCacheFOServiceRunException() throws Exception {
        WarehouseCacheFOServiceUpdateTask mockUpdateTaskFOService;
        WarehouseCache mockClientCache;
        mockUpdateTaskFOService = Mockito.mock(WarehouseCacheFOServiceUpdateTask.class);
        mockClientCache = Mockito.mock(WarehouseCache.class);


        Mockito.doThrow(ExecutionException.class)
                .when(mockClientCache).updateWarehouseCountryCodeCacheFOService();
        //clientCache.updateWarehouseCountryCodeCacheFOService();
        //Mockito.doThrow( ExecutionException.class )
          //      .when(mockUpdateTaskFOService).run();
        mockClientCache.updateWarehouseCountryCodeCacheFOService();
        mockUpdateTaskFOService.run();

    }

最佳答案

您的测试预期此结果是错误的

@Test(expected = ExecutionException.class)

如果你回顾一下你的代码,你会发现你捕获、记录并吞下了该异常。它永远不会被重新抛出,因此您的测试不应期望它。

除此之外,您的测试看起来大体正确。由于记录器是静态的,因此您无法做出任何有意义的断言。

以下内容有点误导

Mockito.doThrow(ExecutionException.class)

由于 ExecutionException,您试图捕获一个异常,而 Retryer 应该用它来包装原始异常。您当前模拟的是包装 ExecutionExceptionExecutionException。它对您的测试有用,但不现实。我会抛出一个通用的 Exception.class(然后将被包装)。

<小时/>

您的代码中有一个小错误,会导致误导性日志记录。即使抛出、捕获和记录异常,该行也会执行。

LOG.info("Cache has been updated.");

您有两个选择,您可以在 catch 中添加 return ,或者移动日志记录行。

try {
    retryer.call(updateCache);
    LOG.info("Cache has been updated."); // this
} catch (ExecutionException | RetryException e) {
    e.printStackTrace();
    LOG.error(e);
    LOG.error("Exception when refreshing the cache.");
    return; // or this
}

关于java - 使用 EasyMock 或 Mockito 模拟 void 方法的 try catch block 并捕获异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61466502/

相关文章:

java - 如何在java中将多级xml扁平化为List<String xpath>?

java - 将 XML 解析为 JSON

java - 为什么我在两个整数值之间的比较不起作用?

java - 如何使用不同的参数运行选定的 junit 测试

gradle - 将JUnit4.12 + Gradle4.9运行到NoSuchFileException中的嵌入式Cassandra单元测试

java - 如何使用 Mockito 匹配二维数组参数?

java - List<Dog> 是 List<Animal> 的子类吗?为什么 Java 泛型不是隐式多态的?

java - 如何在 MicronautTest 中设置 @Value?

c# - 模拟对具有 List 类型属性的对象的调用

java - Mockito 验证参数包含另一个忽略大小写的字符串