如何使用JUnit/Mockito测试模拟只抛出一次异常?

2022-09-03 18:35:54

我进行了简单的重试,因为该操作很少会失败。简化的代码如下。该方法可能会意外引发异常,在这种情况下,重试应允许再次调用此方法。是否可以为此编写 JUnit 测试?我知道使用Mockito库,我们可以强制抛出一个调用方法的异常,但是如何强制这个异常只抛出一次?putObject

public class RetryExample {
Bucket bucket = new Bucket();
static int INTERNAL_EXCEPTION_CODE = 100;
class AException extends RuntimeException {
    private static final long serialVersionUID = 1L;
    int statusCode;
    public int getStatusCode() {
        return statusCode;
    }
}

class Bucket {
    public void putObject(String fileName, byte[] data) throws AException {
        System.out.println("PutObject=" + fileName + " data=" + data);
    }
}

public void process(String fileName, byte[] data) throws AException {
    try {
        retryOperation((f, d) -> bucket.putObject(f, d), fileName, data);
    } catch (Exception ex) {
        throw new AException("Failed to write data", ex);
    }
}

private <T, U> void retryOperation(BiConsumer<T, U> biConsumer, T t, U u) {
    int retries = 0;
    boolean retry = false;
    AException lastServiceException = null;
    do {
        try {
            biConsumer.accept(t, u);
        } catch (AException e) {
            lastServiceException = e;
            int statusCode = e.getStatusCode();
            if (statusCode == INTERNAL_EXCEPTION_CODE) {
                throw e;
            } else {
                break;
            }
        }
        retries++;
        if (retries >= 3) {
            retry = false;
        }
    } while (retry);
    if (lastServiceException != null) {
        throw lastServiceException;
    }
}

测试类:

public class RetryExampleTest {
...
@Test
public void test() {
    RetryExample retryExample = new RetryExample();
    String fileName = "TestFile";
    byte[] data = simulatedPayload(10000);
    try {
        retryExample.process(fileName, data);
    } catch (Exception e) {
        fail("Exception thrown=" + e);
    }
}

答案 1

根据 Mockito 文档,您可以为连续的方法调用设置不同的行为。

when(mock.someMethod("some arg"))
    .thenThrow(new RuntimeException())
    .thenReturn("foo");

在void方法的情况下,你可以做类似的事情(Mockito文档)

doThrow(new RuntimeException())
    .doNothing()
    .when(mock).doSomething();

答案 2

我认为你可以使用全局数据对象来存储抛出异常的时间,所以在 Mockito 库中调用 Exception 方法只是取全局数据对象来记录时间。这很简单。一切都由您的控制。


推荐