Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to simulate throwing an exception only once in retry with JUnit/Mockito test?

I put a simple retry because the operation can rarely fail. The simplified code is below. The method putObject can accidentally throw an exception, in this case the retry should allow to invoke this method again. Is it possible to write a JUnit test for this? I know that with Mockito library we can force to throw an Exception invoking a method but how to force this exception to be thrown only once?

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;
    }
}

Test Class:

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);
    }
}
like image 384
Alex Avatar asked Oct 26 '17 23:10

Alex


People also ask

How do you write JUnit for throwing exception?

In order to test the exception thrown by any method in JUnit 4, you need to use @Test(expected=IllegalArgumentException. class) annotation. You can replace IllegalArgumentException. class with any other exception e.g. NullPointerException.

How do I ignore an exception in Mockito?

If you want to ignore a test method, use @Ignore along with @Test annotation. If you want to ignore all the tests of class, use @Ignore annotation at the class level.


1 Answers

According to the Mockito documentation you can set different behavior for consecutive method calls.

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

In case of a void method you can do something similar (Mockito documentation)

doThrow(new RuntimeException())
    .doNothing()
    .when(mock).doSomething();
like image 193
Stefan Birkner Avatar answered Sep 20 '22 15:09

Stefan Birkner