如何在JUNIT/Mockito测试的重试中模拟抛出异常一次?

Ale*_*lex 5 java junit mockito

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

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

测试类:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*ner 13

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

when(mock.someMethod("some arg"))
    .thenThrow(new RuntimeException())
    .thenReturn("foo");
Run Code Online (Sandbox Code Playgroud)

如果是void方法,你可以做类似的事情(Mockito文档)

doThrow(new RuntimeException())
    .doNothing()
    .when(mock).doSomething();
Run Code Online (Sandbox Code Playgroud)