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()
}