Home Arrow Icon Knowledge base Arrow Icon Global Arrow Icon Can I create a custom matcher that works with any() in Mockito


Can I create a custom matcher that works with any() in Mockito


Creating a custom matcher that works with `any()` in Mockito involves implementing the `ArgumentMatcher` interface. However, using Mockito's built-in matchers like `any()` directly within a custom matcher is challenging due to how Mockito handles matchers through side effects. Here's a detailed guide on how to approach this:

Understanding Mockito's Built-in Matchers

Mockito provides several built-in matchers such as `any()`, `eq()`, `anyInt()`, `anyString()`, etc. These matchers are used to stub or verify methods with generic or specific arguments. For example, `any()` can match any object, while `eq()` matches a specific value.

java
when(mockFoo.bool(eq("false"), anyInt(), any(Object.class))).thenReturn(false);

Creating a Custom Matcher

To create a custom matcher, you implement the `ArgumentMatcher` interface. This interface has a single method `matches(T argument)` that you need to implement to define your matching logic.

java
import org.mockito.ArgumentMatcher;

public class CustomMatcher extends ArgumentMatcher {
    @Override
    public boolean matches(Object argument) {
        // Implement your custom matching logic here
        // For example, checking if the argument is a certain type
        return argument instanceof String;
    }
}

Using `argThat()` for Custom Matchers

To use your custom matcher in Mockito, you wrap it with `argThat()`. This allows you to integrate your custom logic into Mockito's stubbing or verification process.

java
when(mockFoo.doSomething(argThat(new CustomMatcher()))).thenReturn("Result");

Combining Custom Matchers with Built-in Matchers

While you can't directly use Mockito's built-in matchers like `any()` inside your custom matcher due to their side-effect nature, you can use them alongside your custom matchers in the same method call. For example:

java
when(mockFoo.doSomething(anyInt(), argThat(new CustomMatcher()))).thenReturn("Result");

Limitations with Mockito's Built-in Matchers

Mockito's built-in matchers like `any()` are designed to work within Mockito's framework and are not easily consumable outside of it. If you need to combine custom logic with Mockito's matchers, consider using Hamcrest matchers, which are more flexible and can be used with Mockito via `MockitoHamcrest.argThat()`.

Example of Using Hamcrest with Mockito

If you want to use matchers that can be combined more flexibly, consider using Hamcrest matchers. Here's an example of using a Hamcrest matcher with Mockito:

java
import org.hamcrest.Matcher;
import org.mockito.MockitoHamcrest;

// Assuming you have a Hamcrest matcher
Matcher hamcrestMatcher = org.hamcrest.Matchers.equalTo("expected");

when(mockFoo.doSomething(MockitoHamcrest.argThat(hamcrestMatcher))).thenReturn("Result");

Conclusion

While you can't directly use Mockito's `any()` inside a custom matcher due to its implementation, you can still create custom matchers and use them alongside Mockito's built-in matchers. For more complex logic, consider using Hamcrest matchers, which offer greater flexibility.

Citations:
[1] https://www.digitalocean.com/community/tutorials/mockito-argument-matchers-any-eq
[2] https://groups.google.com/g/mockito/c/LJyOAJYR-54
[3] https://mockk.io
[4] https://github.com/mockito/mockito/issues/3080
[5] https://www.youtube.com/watch?v=_-EKS7kkeKo
[6] https://stackoverflow.com/questions/37205832/how-to-create-custom-matchers-in-mockito
[7] https://www.softwaretestinghelp.com/mockito-matchers/
[8] https://site.mockito.org/javadoc/current/index.html?org%2Fmockito%2FArgumentMatcher.html
[9] https://stackoverflow.com/questions/39398513/how-can-i-create-a-custom-argumentmatcher-that-accepts-arguments-from-other-matc
[10] https://kenkousen.substack.com/p/tales-from-the-jar-side-a-mockito