Home Arrow Icon Knowledge base Arrow Icon Global Arrow Icon How can I use thenThrow() with thenReturn() in the same test


How can I use thenThrow() with thenReturn() in the same test


Using `thenThrow()` and `thenReturn()` in the same test with Mockito allows you to simulate different behaviors for consecutive calls to a mocked method. This is particularly useful when testing scenarios where a method might fail initially but succeed on subsequent attempts. Here's how you can achieve this:

Understanding `thenThrow()` and `thenReturn()`

- `thenThrow()`: This method is used to specify that a mock should throw an exception when its method is called. It's commonly used to test error handling in your code.

- `thenReturn()`: This method is used to specify a return value for a mock method. You can chain multiple `thenReturn()` calls to define different return values for consecutive method calls.

Using `thenThrow()` and `thenReturn()` Together

To use both `thenThrow()` and `thenReturn()` in the same test, you need to chain them in a specific order. The first call to the mocked method will throw an exception, and subsequent calls will return the specified value(s).

Here is an example:

java
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class MyServiceTest {

    @Mock
    private MyDependency myDependency;

    @Test
    void testConsecutiveCalls() {
        // First call throws an exception, second call returns a value
        when(myDependency.doSomething()).thenThrow(new RuntimeException("First call failed"))
                .thenReturn("Success on second call");

        // Simulate first call
        try {
            myDependency.doSomething();
        } catch (RuntimeException e) {
            System.out.println("Caught exception: " + e.getMessage());
        }

        // Simulate second call
        String result = myDependency.doSomething();
        System.out.println("Result on second call: " + result);
    }
}

In this example, the first call to `myDependency.doSomething()` will throw a `RuntimeException`, and the second call will return the string `"Success on second call"`.

Best Practices

While it's technically possible to use both `thenThrow()` and `thenReturn()` in the same test, it's generally recommended to keep tests focused on a single scenario. This means you might want to consider writing separate tests for the exception case and the success case. However, if your test scenario genuinely requires simulating both behaviors in sequence, the approach above works well.

Using `thenAnswer()` for Custom Behavior

If you need more complex logic, such as changing behavior based on some condition or state, you might want to use `thenAnswer()` instead. This allows you to provide a custom implementation of the `Answer` interface to handle the method call.

java
when(myDependency.doSomething()).thenAnswer(invocation -> {
    // Custom logic here, e.g., throw an exception on first call
    static boolean firstCall = true;
    if (firstCall) {
        firstCall = false;
        throw new RuntimeException("First call failed");
    } else {
        return "Success on subsequent calls";
    }
});

This approach gives you more flexibility but can make your tests more complex.

Citations:
[1] https://stackoverflow.com/questions/45597061/java-mock-throw-an-exception-then-return-a-value
[2] https://www.vogella.com/tutorials/Mockito/article.html
[3] https://dev.to/realnamehidden1_61/thenthrow-method-in-mockito-example-460l
[4] https://reflectoring.io/clean-unit-tests-with-mockito/
[5] https://www.toptal.com/java/a-guide-to-everyday-mockito
[6] https://stackoverflow.com/questions/4180209/mockito-re-stub-method-already-stubbed-with-thenthrow
[7] https://www.baeldung.com/mockito-exceptions
[8] https://www.lambdatest.com/automation-testing-advisor/selenium/methods/org.mockito.Mockito.doReturn