The method takes input or arguments which governs the behavior of the method. Mockito by default validates the arguments using java defined way ie with the help of equals method, which is also a recommended way of doing, it keeps tests clean and simple.
Mockito provides us a way to capture arguments passed in the test cases, which can further use to validate and asserts. Argument Captor can be created in 2 ways.
@Captor
ArgumentCaptor#forClass
ArgumentCaptor#forClass
package com.example.mokito3.sujan;
public class AppleService {
String saveApple(String apple) {
String appleString = "i love " + apple + " apple";
return appleString;
}
}
package com.example.mokito3.sujan;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
public class AppleServiceTest {
@Mock
private AppleService appleService;
@Test
void saveAppleMockTest() {
when(appleService.saveApple("Macintosh")).thenReturn("i eat apple");
appleService.saveApple("Macintosh");
ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
verify(appleService).saveApple(argumentCaptor.capture());
System.out.println("argumentCaptor = " + argumentCaptor.getValue());
assertEquals("Macintosh", argumentCaptor.getValue());
}
}
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()
}
@Captor
@Captor
annotation provides a easy and clean way to create Argument Captor.
package com.example.mokito3.sujan;
public abstract class AppleService {
String saveApple(String apple) {
String appleString = "i love " + apple + " apple";
return appleString;
}
}
package com.example.mokito3.sujan;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
public class AppleServiceTest {
@Captor
ArgumentCaptor<String> argumentCaptor;
@Mock
private AppleService appleService;
@Test
void saveAppleMockTest() {
when(appleService.saveApple("Macintosh")).thenReturn("i eat apple");
appleService.saveApple("Macintosh");
ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
verify(appleService).saveApple(argumentCaptor.capture());
System.out.println("argumentCaptor = " + argumentCaptor.getValue());
assertEquals("Macintosh", argumentCaptor.getValue());
}
}
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()
}
Argument Captor for User Defined Class
Argument capture is not only limited to java defined classes, but it can also be used to capture arguments for classes created by developers as well.
package com.example.mokito3.sujan;
import java.util.Objects;
public class Apple {
private int appleNo;
private String appleName;
public Apple(int appleNo, String appleName) {
this.appleNo = appleNo;
this.appleName = appleName;
}
public int getAppleNo() {
return appleNo;
}
public String getAppleName() {
return appleName;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Apple apple = (Apple) o;
return appleNo == apple.appleNo &&
Objects.equals(appleName, apple.appleName);
}
@Override
public int hashCode() {
return Objects.hash(appleNo, appleName);
}
@Override
public String toString() {
return "Apple{" +
"appleNo=" + appleNo +
", appleName='" + appleName + '\'' +
'}';
}
}
package com.example.mokito3.sujan;
public abstract class AppleService {
String saveApple(Apple apple) {
String appleString = "apple No is:- " + apple.getAppleNo() + " apple Name is:- " + apple.getAppleName();
return appleString;
}
}
package com.example.mokito3.sujan;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
public class AppleServiceTest {
@Mock
private AppleService appleService;
@Test
void saveAppleMockTest() {
Apple apple=new Apple(1, "Macintosh");
when(appleService.saveApple(apple)).thenReturn("i eat apple");
appleService.saveApple(apple);
ArgumentCaptor<Apple> argumentCaptor = ArgumentCaptor.forClass(Apple.class);
verify(appleService).saveApple(argumentCaptor.capture());
System.out.println("argumentCaptor = " + argumentCaptor.getValue());
assertEquals(apple, argumentCaptor.getValue());
}
}
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()
}
Argument Captor for Multiple Calls
We call a method multiple times with different arguments, if we need to capture all the arguments in order to further assert them, Mockito provides us ArgumentCaptor#getAllValues()
method. It will capture all the arguments passed as input to the mock method.
package com.example.mokito3.sujan;
public abstract class AppleService {
String saveApple(String apple) {
String appleString = "i love " + apple + " apple";
return appleString;
}
}
package com.example.mokito3.sujan;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Arrays;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
public class AppleServiceTest {
@Mock
private AppleService appleService;
@Test
void saveAppleMockTest() {
when(appleService.saveApple("Macintosh")).thenReturn("i eat apple");
appleService.saveApple("Macintosh");
appleService.saveApple("Fuji");
appleService.saveApple("Gala");
ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
verify(appleService, times(3)).saveApple(argumentCaptor.capture());
System.out.println("argumentCaptor = " + argumentCaptor.getAllValues());
assertEquals(Arrays.asList("Macintosh", "Fuji", "Gala"), argumentCaptor.getAllValues());
}
}
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()
}
Argument Captor for Variable Arguments or Varargs
Methods can take a single input, list of input, or array since java 1. In java 5, a new way of passing array was introduced, Variable Arguments or in short Varargs. Mockito Argument Captor can be used to capture Varargs arguments as well.
package com.example.mokito3.sujan;
public abstract class AppleService {
String saveApple(String... apple) {
String appleString = "i love " + apple + " apple";
return appleString;
}
}
package com.example.mokito3.sujan;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Arrays;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
public class AppleServiceTest {
@Mock
private AppleService appleService;
@Test
void saveAppleMockTest() {
when(appleService.saveApple("Macintosh", "Fuji", "Gala")).thenReturn("i eat apple");
appleService.saveApple("Macintosh", "Fuji", "Gala");
ArgumentCaptor<String[]> argumentCaptor = ArgumentCaptor.forClass(String[].class);
verify(appleService).saveApple(argumentCaptor.capture());
System.out.println("argumentCaptor = " + argumentCaptor.getAllValues());
assertEquals(Arrays.asList("Macintosh", "Fuji", "Gala"), argumentCaptor.getAllValues());
}
}
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()
}
Argument Captor with stubbing
ArgumentCapture
is a suitable way to capture the argument passed as a parameter so that it can be used further for assertions, but ArgumentCaptor
should never be used with stubbing because if stub never called then ArgumentCapture
will be null and test case might throw NullPointerException.
ArgumentCaptor should never be used with stubbing
package com.example.mokito3.sujan;
public class AppleService {
String saveApple(String apple) {
String appleString = "i love " + apple + " apple";
return appleString;
}
}
package com.example.mokito3.sujan;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
public class AppleServiceTest {
@Captor
ArgumentCaptor<String> argumentCaptor;
@Mock
private AppleService appleService;
@Test
void saveAppleMethodMockTest() {
/* never use argumentCaptor while stubbing */
when(appleService.saveApple("Macintosh")).thenReturn("i eat apple");
/* stub never invoked
appleService.saveApple("Macintosh");*/
ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
verify(appleService).saveApple(argumentCaptor.capture());
System.out.println("argumentCaptor = " + argumentCaptor.getValue());
assertEquals("Macintosh", argumentCaptor.getValue());
}
@Test
void saveAppleAnnotationMockTest() {
/* never use argumentCaptor while stubbing */
when(appleService.saveApple(argumentCaptor.capture())).thenReturn("i eat apple");
/* stub never invoked
appleService.saveApple("Macintosh");*/
verify(appleService).saveApple(argumentCaptor.capture());
System.out.println("argumentCaptor = " + argumentCaptor.getValue());
assertEquals("Macintosh", argumentCaptor.getValue());
}
}
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()
}