Home Arrow Icon Knowledge base Arrow Icon Global Arrow Icon How can I use Mockito argument matchers to test methods with multiple parameters


How can I use Mockito argument matchers to test methods with multiple parameters


Using Mockito argument matchers is a powerful way to test methods with multiple parameters by allowing you to stub behaviors for a wide range of input values. Here's a detailed guide on how to use them effectively:

Understanding Mockito Argument Matchers

Mockito argument matchers are static methods in the `org.mockito.ArgumentMatchers` class that help you define how method arguments should be matched during stubbing or verification. Common matchers include `any()`, `anyString()`, `anyInt()`, and `eq()`.

Using Argument Matchers with Multiple Parameters

When a method has multiple parameters, you can use argument matchers to define how each parameter should be matched. For example, if you have a method like this:

java
public class MyClass {
    public boolean myMethod(String str, int i, Object obj) {
        // Method implementation
    }
}

You can use Mockito to stub this method using argument matchers like so:

java
MyClass mockMyClass = mock(MyClass.class);
when(mockMyClass.myMethod(anyString(), anyInt(), any(Object.class))).thenReturn(true);

In this example, `anyString()`, `anyInt()`, and `any(Object.class)` are used to match any string, integer, and object respectively. This means that no matter what values are passed to `myMethod`, it will always return `true`.

Mixing Specific Values and Argument Matchers

If you want to match some parameters with specific values and others with matchers, you can do so by using the `eq()` method for specific values. For instance:

java
when(mockMyClass.myMethod(eq("specificString"), anyInt(), any(Object.class))).thenReturn(false);

Here, the method will return `false` only when the string parameter is `"specificString"`, regardless of the integer and object values.

Handling Overlapping Matchers

When defining multiple stubs with overlapping matchers, Mockito will use the first stub it encounters. For example:

java
when(mockMyClass.myMethod(anyString(), anyInt(), any(Object.class))).thenReturn(true);
when(mockMyClass.myMethod(eq("specificString"), anyInt(), any(Object.class))).thenReturn(false);

In this case, the second stub will never be reached because the first stub matches all possible inputs, including `"specificString"`. To avoid this, you can reorder your stubs so that the most specific ones come first, or use a custom matcher to exclude certain values.

Using Argument Captors for Verification

If you need to verify that a method was called with specific arguments, you can use `ArgumentCaptor`. This is particularly useful when testing methods with multiple invocations and different arguments.

java
@Captor
ArgumentCaptor stringCaptor;
@Captor
ArgumentCaptor intCaptor;
@Captor
ArgumentCaptor objectCaptor;

@Test
public void testMyMethod() {
    // Perform method calls
    mockMyClass.myMethod("A", 1, new Object());
    mockMyClass.myMethod("B", 2, new Object());

    // Verify method invocations
    verify(mockMyClass, times(2)).myMethod(stringCaptor.capture(), intCaptor.capture(), objectCaptor.capture());

    // Verify captured arguments
    List strings = stringCaptor.getAllValues();
    List ints = intCaptor.getAllValues();
    List objects = objectCaptor.getAllValues();

    assertEquals("A", strings.get(0));
    assertEquals("B", strings.get(1));
    assertEquals(Integer.valueOf(1), ints.get(0));
    assertEquals(Integer.valueOf(2), ints.get(1));
}

Combining Matchers

Mockito also allows combining matchers using logical operations like `and`, `or`, and `not` from the `org.mockito.AdditionalMatchers` class. This can be useful for creating more complex matching conditions.

java
when(mockMyClass.myMethod(or(eq("A"), eq("B")), anyInt(), any(Object.class))).thenReturn(true);

In this example, the method will return `true` if the string parameter is either `"A"` or `"B"`, regardless of the integer and object values.

By leveraging these features, you can effectively use Mockito argument matchers to test methods with multiple parameters in a flexible and efficient manner.

Citations:
[1] https://www.digitalocean.com/community/tutorials/mockito-argument-matchers-any-eq
[2] https://www.toptal.com/java/a-guide-to-everyday-mockito
[3] https://www.softwaretestinghelp.com/mockito-matchers/
[4] https://stackoverflow.com/questions/40246106/how-does-mockito-handle-overlapping-matchers-with-multiple-arguments-in-the-then
[5] https://jdriven.com/blog/2024/03/Mastering-Mockito-Returning-Fresh-Stream-For-Multiple-Calls-To-Mocked-Method
[6] https://stackoverflow.com/questions/40372421/mockito-argument-matcher-with-multiple-arguments
[7] https://howtodoinjava.com/mockito/verify-multiple-method-arguments/
[8] https://www.javacodegeeks.com/capture-method-arguments-in-mockito-test.html
[9] https://stackoverflow.com/questions/13846837/using-multiple-argumentmatchers-on-the-same-mock/13849384