Mockito 3 Stub with Argument Matchers

Stubbing is great, we can make mock to behave the way we want with required input, but it has some limitations, what if input value changes, we cant stub for all possible values, or in other terms, how to make generic stubs, which will work for entire type.

Mockito provides ArgumentMatchers. Stubing  ArgumentMatchers gives a convenient way to make stubs for generic types, it matches for all arguments of a type.

ArgumentMatchers for String

we can stub the mock object for any non-null string type. ArgumentMatcher provides a lot of different string methods.

package com.example.mokito3.sujan;

public class AppleService {
    public String processApple(String appleName) {
        return "I love " + appleName + " Apple";
    }
}
package com.example.mokito3.sujan;

import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatchers;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class AppleServiceTest {
    @Test
    void saveAppleWithMockTest() {
        AppleService appleService = mock(AppleService.class);
        when(appleService.processApple(ArgumentMatchers.anyString())).thenReturn("i eat apple");
        when(appleService.processApple(ArgumentMatchers.endsWith("sh"))).thenReturn("i eat macintosh apple");
        when(appleService.processApple(ArgumentMatchers.contains("ji"))).thenReturn("i eat fuji apple");
        when(appleService.processApple(ArgumentMatchers.startsWith("ga"))).thenReturn("i eat gala apple");
        assertEquals("i eat apple", appleService.processApple(new String()));
        assertEquals("i eat macintosh apple", appleService.processApple("macintosh"));
        assertEquals("i eat fuji apple", appleService.processApple("fuji"));
        assertEquals("i eat gala apple", appleService.processApple("gala"));
    }
}
plugins {
    id 'java'
}

group 'org.example'
version '1.0-SNAPSHOT'

repositories { jcenter() }
dependencies {
    testImplementation('org.junit.jupiter:junit-jupiter:5.6.2')
    testCompile 'org.mockito:mockito-junit-jupiter:3.4.4'
}
test {
    useJUnitPlatform()
}

 

ArgumentMatchers for primitive types

ArgumentMatcher provides overloaded method for almost all types of primtive types.

package com.example.mokito3.sujan;

public class AppleService {
    public String processApple(short appleName) {
        return "I love " + appleName + " Apple";
    }

    public String processApple(long appleName) {
        return "I love " + appleName + " Apple";
    }

    public String processApple(float appleName) {
        return "I love " + appleName + " Apple";
    }

    public String processApple(int appleName) {
        return "I love " + appleName + " Apple";
    }

    public String processApple(double appleName) {
        return "I love " + appleName + " Apple";
    }

    public String processApple(char appleName) {
        return "I love " + appleName + " Apple";
    }

    public String processApple(byte appleName) {
        return "I love " + appleName + " Apple";
    }

    public String processApple(boolean appleName) {
        return "I love " + appleName + " Apple";
    }
}
package com.example.mokito3.sujan;

import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatchers;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class AppleServiceTest {
    @Test
    void saveAppleWithMockTest() {
        AppleService appleService = mock(AppleService.class);
        when(appleService.processApple(ArgumentMatchers.eq(true))).thenReturn("its a boolean");
        when(appleService.processApple(ArgumentMatchers.eq((byte) 1))).thenReturn("its a byte");
        when(appleService.processApple(ArgumentMatchers.eq('a'))).thenReturn("its a char");
        when(appleService.processApple(ArgumentMatchers.eq((double) 1))).thenReturn("its a double");
        when(appleService.processApple(ArgumentMatchers.eq(1))).thenReturn("its an int");
        when(appleService.processApple(ArgumentMatchers.eq(1f))).thenReturn("its a float");
        when(appleService.processApple(ArgumentMatchers.eq(1l))).thenReturn("its a long");
        when(appleService.processApple(ArgumentMatchers.eq((short) 1))).thenReturn("its a short");
        assertEquals("its a boolean", appleService.processApple(true));
        assertEquals("its a byte", appleService.processApple((byte) 1));
        assertEquals("its a char", appleService.processApple('a'));
        assertEquals("its a double", appleService.processApple((double) 1));
        assertEquals("its an int", appleService.processApple(1));
        assertEquals("its a float", appleService.processApple((float) 1));
        assertEquals("its a long", appleService.processApple((long) 1));
        assertEquals("its a short", appleService.processApple((short) 1));
    }
}
plugins {
    id 'java'
}

group 'org.example'
version '1.0-SNAPSHOT'

repositories { jcenter() }
dependencies {
    testImplementation('org.junit.jupiter:junit-jupiter:5.6.2')
    testCompile 'org.mockito:mockito-junit-jupiter:3.4.4'
}
test {
    useJUnitPlatform()
}

ArgumentMatcher also provides overloaded method to create generic stubs of primtive types.

package com.example.mokito3.sujan;

public class AppleService {
    public String processApple(short appleName) {
        return "I love " + appleName + " Apple";
    }

    public String processApple(long appleName) {
        return "I love " + appleName + " Apple";
    }

    public String processApple(float appleName) {
        return "I love " + appleName + " Apple";
    }

    public String processApple(int appleName) {
        return "I love " + appleName + " Apple";
    }

    public String processApple(double appleName) {
        return "I love " + appleName + " Apple";
    }

    public String processApple(char appleName) {
        return "I love " + appleName + " Apple";
    }

    public String processApple(byte appleName) {
        return "I love " + appleName + " Apple";
    }

    public String processApple(boolean appleName) {
        return "I love " + appleName + " Apple";
    }
}
package com.example.mokito3.sujan;

import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatchers;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class AppleServiceTest {
    @Test
    void saveAppleWithMockTest() {
        AppleService appleService = mock(AppleService.class);
        when(appleService.processApple(ArgumentMatchers.anyBoolean())).thenReturn("its a boolean");
        when(appleService.processApple(ArgumentMatchers.anyByte())).thenReturn("its a byte");
        when(appleService.processApple(ArgumentMatchers.anyChar())).thenReturn("its a char");
        when(appleService.processApple(ArgumentMatchers.anyDouble())).thenReturn("its a double");
        when(appleService.processApple(ArgumentMatchers.anyInt())).thenReturn("its an int");
        when(appleService.processApple(ArgumentMatchers.anyFloat())).thenReturn("its a float");
        when(appleService.processApple(ArgumentMatchers.anyLong())).thenReturn("its a long");
        when(appleService.processApple(ArgumentMatchers.anyShort())).thenReturn("its a short");
        assertEquals("its a boolean", appleService.processApple(true));
        assertEquals("its a byte", appleService.processApple((byte) 1));
        assertEquals("its a char", appleService.processApple('a'));
        assertEquals("its a double", appleService.processApple((double) 1));
        assertEquals("its an int", appleService.processApple(1));
        assertEquals("its a float", appleService.processApple(1f));
        assertEquals("its a long", appleService.processApple((long) 1));
        assertEquals("its a short", appleService.processApple((short) 1));
    }
}
plugins {
    id 'java'
}

group 'org.example'
version '1.0-SNAPSHOT'

repositories { jcenter() }
dependencies {
    testImplementation('org.junit.jupiter:junit-jupiter:5.6.2')
    testCompile 'org.mockito:mockito-junit-jupiter:3.4.4'
}
test {
    useJUnitPlatform()
}

 

ArgumentMatchers for Collection

ArgumentMatcher provides lots of overloaded methods for collection types.

package com.example.mokito3.sujan;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class AppleService {

    public String processApple(Collection appleName) {
        return "I love " + appleName + " Apple";
    }

    public String processApple(List appleName) {
        return "I love " + appleName + " Apple";
    }

    public String processApple(Map appleName) {
        return "I love " + appleName + " Apple";
    }

    public String processApple(Set appleName) {
        return "I love " + appleName + " Apple";
    }

    public String processApple(Iterable appleName) {
        return "I love " + appleName + " Apple";
    }
}
package com.example.mokito3.sujan;

import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatchers;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class AppleServiceTest {
    @Test
    void saveAppleWithMockTest() {
        AppleService appleService = mock(AppleService.class);
        when(appleService.processApple(ArgumentMatchers.anyCollection())).thenReturn("its a collection");
        when(appleService.processApple(ArgumentMatchers.anyList())).thenReturn("its a list");
        when(appleService.processApple(ArgumentMatchers.anyMap())).thenReturn("its a map");
        when(appleService.processApple(ArgumentMatchers.anySet())).thenReturn("its a set");
        when(appleService.processApple(ArgumentMatchers.anyIterable())).thenReturn("its an iterable");
        Collection collection = new ArrayList();
        List list = new ArrayList<>();
        Map map = new HashMap();
        Set set = new HashSet();
        Iterable iterable = new ArrayList();
        assertEquals("its a collection", appleService.processApple(collection));
        assertEquals("its a list", appleService.processApple(list));
        assertEquals("its a map", appleService.processApple(map));
        assertEquals("its a set", appleService.processApple(set));
        assertEquals("its an iterable", appleService.processApple(iterable));
    }
}
plugins {
    id 'java'
}

group 'org.example'
version '1.0-SNAPSHOT'

repositories { jcenter() }
dependencies {
    testImplementation('org.junit.jupiter:junit-jupiter:5.6.2')
    testCompile 'org.mockito:mockito-junit-jupiter:3.4.4'
}
test {
    useJUnitPlatform()
}

Stub for multiple ArgumentMatcher

we can stub for multiple or overloaded methods with ArgumentMatcher.

package com.example.mokito3.sujan;

import java.util.Collection;

public class AppleService {
    public String processApple(String appleName, int i, Collection collection) {
        return "I love Apple";
    }
}
package com.example.mokito3.sujan;

import org.junit.jupiter.api.Test;

import static org.mockito.ArgumentMatchers.anyCollection;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class AppleServiceTest {
    @Test
    void saveAppleWithMockTest() {
        AppleService appleService = mock(AppleService.class);
        when(appleService.processApple(anyString(), anyInt(), anyCollection())).thenReturn("i eat apple");
    }
}
plugins {
    id 'java'
}

group 'org.example'
version '1.0-SNAPSHOT'

repositories { jcenter() }
dependencies {
    testImplementation('org.junit.jupiter:junit-jupiter:5.6.2')
    testCompile 'org.mockito:mockito-junit-jupiter:3.4.4'
}
test {
    useJUnitPlatform()
}

 

ArgumentMatcher Limitation

ArgumentMatcher works great, we can match almost any type of argument, but it has a few limitations. Methods with multiple parameters must have to use ArgumentMatcher for all input. combination of ArgumentMatcher with predefined stub can't be used or else it will throw InvalidUseOfMatchersException.

package com.example.mokito3.sujan;

public class AppleService {
    public String processApple(int appleNo, String appleName) {
        return "I have " + appleNo + " " + appleName + " Apple";
    }
}
package com.example.mokito3.sujan;

import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatchers;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;

import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;

@MockitoSettings(strictness = Strictness.LENIENT)
public class AppleServiceTest {
    @Mock
    private AppleService appleService;

    @Test
    void saveAppleWithStaticMockTest() {
        /* valid */
        when(appleService.processApple(anyInt(), anyString())).thenReturn("i eat apple");
        /* valid */
        when(appleService.processApple(anyInt(), eq("Macintosh"))).thenReturn("i eat apple");
        /* in valid */
        when(appleService.processApple(ArgumentMatchers.anyInt(), "Macintosh")).thenReturn("i eat apple");
    }
}
plugins {
    id 'java'
}

group 'org.example'
version '1.0-SNAPSHOT'

repositories { jcenter() }
dependencies {
    testImplementation('org.junit.jupiter:junit-jupiter:5.6.2')
    testCompile 'org.mockito:mockito-junit-jupiter:3.4.4'
}
test {
    useJUnitPlatform()
}

follow us on