Home Arrow Icon Knowledge base Arrow Icon Global Arrow Icon Can I use Mockito to simulate a sequence of successful and failed API calls


Can I use Mockito to simulate a sequence of successful and failed API calls


Yes, you can use Mockito to simulate a sequence of successful and failed API calls. Mockito allows you to define different behaviors for each call to a mock object. Here's how you can achieve this:

Basic Example

Let's say you have a method `doTheCall()` in your mock object that you want to simulate as failing on the first call and succeeding on the second call.

java
// Create a mock object
MyService myMock = Mockito.mock(MyService.class);

// Define the behavior for the first call to fail
// and the second call to succeed
Mockito.when(myMock.doTheCall())
       .thenReturn("Failed") // First call returns "Failed"
       .thenReturn("Success"); // Second call returns "Success"

// Now, when you call doTheCall() twice, it will behave as defined
String firstCallResult = myMock.doTheCall(); // Returns "Failed"
String secondCallResult = myMock.doTheCall(); // Returns "Success"

Simulating Exceptions

If you want to simulate an exception on the first call instead of returning a specific value, you can use `doThrow()`:

java
// Create a mock object
MyService myMock = Mockito.mock(MyService.class);

// Define the behavior for the first call to throw an exception
// and the second call to succeed
Mockito.doThrow(new RuntimeException("First call failed"))
        .doNothing()
        .when(myMock).doTheCall();

// Now, when you call doTheCall() twice, it will behave as defined
try {
    myMock.doTheCall(); // Throws RuntimeException
} catch (RuntimeException e) {
    System.out.println(e.getMessage()); // Prints "First call failed"
}

myMock.doTheCall(); // Does nothing (no exception or return value)

However, if you want to return a value on the second call, you should use `thenReturn()` after `doThrow()`:

java
// Define the behavior for the first call to throw an exception
// and the second call to return a value
Mockito.doThrow(new RuntimeException("First call failed"))
        .thenReturn("Success")
        .when(myMock).doTheCall();

// Now, when you call doTheCall() twice, it will behave as defined
try {
    myMock.doTheCall(); // Throws RuntimeException
} catch (RuntimeException e) {
    System.out.println(e.getMessage()); // Prints "First call failed"
}

String secondCallResult = myMock.doTheCall(); // Returns "Success"

Testing a Sequence of Calls

If you need to test a sequence where the first call fails, the second call succeeds, and subsequent calls also succeed, you can chain the `thenReturn()` calls:

java
// Define the behavior for the first call to fail
// and subsequent calls to succeed
Mockito.when(myMock.doTheCall())
       .thenReturn("Failed") // First call returns "Failed"
       .thenReturn("Success") // Second call returns "Success"
       .thenReturn("Success"); // Third and subsequent calls return "Success"

// Now, when you call doTheCall() multiple times, it will behave as defined
String firstCallResult = myMock.doTheCall(); // Returns "Failed"
String secondCallResult = myMock.doTheCall(); // Returns "Success"
String thirdCallResult = myMock.doTheCall(); // Returns "Success"

However, if you want all calls after the first to succeed without specifying each one, you can use the fact that the last argument to `thenReturn()` is used for all subsequent calls:

java
// Define the behavior for the first call to fail
// and all subsequent calls to succeed
Mockito.when(myMock.doTheCall())
       .thenReturn("Failed") // First call returns "Failed"
       .thenReturn("Success"); // Second and subsequent calls return "Success"

// Now, when you call doTheCall() multiple times, it will behave as defined
String firstCallResult = myMock.doTheCall(); // Returns "Failed"
String secondCallResult = myMock.doTheCall(); // Returns "Success"
String thirdCallResult = myMock.doTheCall(); // Returns "Success"

Conclusion

Mockito provides a flexible way to simulate sequences of API calls with different outcomes, making it easier to test complex scenarios in your application. By chaining `thenReturn()` or combining `doThrow()` with `thenReturn()`, you can mimic real-world API behavior and ensure your application handles various responses correctly.

Citations:
[1] https://www.thegreenreport.blog/articles/challenges-and-benefits-of-mocking-external-services-with-examples/challenges-and-benefits-of-mocking-external-services-with-examples.html
[2] https://stackoverflow.com/questions/11785498/simulate-first-call-fails-second-call-succeeds
[3] https://www.youtube.com/watch?v=vcRFkp8jHJ8
[4] https://stackoverflow.com/questions/11785498/simulate-first-call-fails-second-call-succeeds/41272746
[5] https://www.vogella.com/tutorials/Mockito/article.html
[6] https://docs.flutter.dev/cookbook/testing/unit/mocking
[7] https://stackoverflow.com/questions/30240989/unit-testing-with-junit-and-mockito-for-external-rest-api-calls
[8] https://github.com/dart-lang/mockito/issues/260