Mockito is a popular mocking framework in Java.
In this article, we will learn how to use Mockito Annotation, @Mock
, @Spy
, @Captor
, and @InjectMocks
.
Setting to use Annotation
Setting is required to use annotations such as @Mock
in the Mockito library.
If @Mock
is used without this setting, NullPointerException will occur.
You can select one of the methods introduced below and apply it to the test code.
1. MockitoJUnit.rule
If you define @Rule
as follows, you can use annotations such as @Mock
.
We recommend that you use this method whenever possible.
public class MockitoTest {
@Rule
public MockitoRule initRule = MockitoJUnit.rule();
....
}
2. MockitoAnnotations.initMocks
Another way is to call initMocks(this)
before the test is run, like this:
public class MockitoTest {
@Before
public void init() {
MockitoAnnotations.initMocks(this);
}
}
3. MockitoJUnitRunner
There is also a way to set it to MockitoJUnitRunner in @RunWith
like this:
If you use this method, it is better to choose one of the above two methods because other JUnitRunners cannot be used.
@RunWith(MockitoJUnitRunner.class)
public class MockitoTest {
...
}
If one of the three above is applied to the test code, you can use annotations such as @Mock
in the test code.
@Mock
I wrote an article in the order of introducing the method not to use Annotation first, and then the method to use Annotation.
Create mock object without using @Mock
The code below creates a mock object without using @Mock
.
@Test
public void mockingList_verify() {
List mockList = mock(ArrayList.class);
mockList.add("apple");
verify(mockList).add("apple");
}
Create mock object with @Mock
You can create a mock object using @Mock
like this:
Using @Mock
allows you to create mock objects with less code.
@Mock
List mockList;
@Test
public void mockingList_verify() {
mockList.add("apple");
verify(mockList).add("apple");
}
The following is an example of stubbing with when
.
@Mock
List mockList;
@Test
public void mockingList_when() {
when(mockList.get(0)).thenReturn("apple");
when(mockList.get(1)).thenReturn("kiwi");
when(mockList.size()).thenReturn(10);
assertEquals("apple", mockList.get(0));
assertEquals("kiwi", mockList.get(1));
assertEquals(10, mockList.size());
}
@Spy
Here is how to create a spy object without @Spy
.
@Test
public void spyingList_verify() {
List spyList = spy(ArrayList.class);
spyList.add("apple");
verify(spyList).add("apple");
}
Create a spy object with @Spy
You can create a spy object using @Spy
like this:
@Spy
List spyList;
@Test
public void spyingList_verify() {
spyList.add("apple");
verify(spyList).add("apple");
}
The following is an example of stubbing with when
.
@Spy
List spyList;
@Test
public void spyingList_when() {
doReturn("apple").when(spyList).get(0);
doReturn("kiwi").when(spyList).get(1);
doReturn(10).when(spyList).size();
assertEquals("apple", spyList.get(0));
assertEquals("kiwi", spyList.get(1));
assertEquals(10, spyList.size());
}
@Captor
Here is the code using ArgumentCaptor without @Captor
.
@Test
public void captorExample() {
ArgumentCaptor<String> arg = ArgumentCaptor.forClass(String.class);
mockList.add("apple");
verify(mockList).add(arg.capture());
assertEquals("apple", arg.getValue());
}
Create ArgumentCaptor object with @Captor
You can create an ArgumentCaptor object using @Captor
like this:
@Captor
ArgumentCaptor argCaptor;
@Test
public void captorAnnotationExample() {
mockList.add("apple");
verify(mockList).add(argCaptor.capture());
assertEquals("apple", argCaptor.getValue());
}
@InjectMocks
Here are the two classes used in this example, Contacts and ContactsDatabase.
public class Contacts {
private ContactsDatabase db;
public Contacts() {
db = new ContactsDatabase();
}
public Contacts(ContactsDatabase db) {
this.db = db;
}
public String getUserInfo(int id) {
String userInfo= "{ " + db.getName(id) + ", "
+ db.getPhoneNumber(id) + " }";
return userInfo;
}
public void addUserInfo(String name, String number) {
db.addUserInfo(name, number);
}
}
public class ContactsDatabase {
List<String> names = new ArrayList<>();
List<String> numbers = new ArrayList<>();
public ContactsDatabase() {
names.add("AAA");
numbers.add("000-1234");
}
public String getName(int id) {
return names.get(id);
}
public String getPhoneNumber(int id) {
return numbers.get(id);
}
public void addUserInfo(String name, String number) {
names.add(name);
numbers.add(number);
}
}
Mock object injection
Inside the Contacts class is a ContactsDatabase object. I want to test the Contacts object, but it is not easy to test because it has a dependency with ContactsDatabase. So, I want to make a Mock of ContactsDatabase to test the functionality of Contacts.
First, make the ContactsDatabase a Mock object, as in the following code: And if you pass a Mock object as an argument of Contacts, Contacts is an actual object, but the ContactsDatabase object inside becomes a mock object.
By making the Mock object return the desired value as when
, you can test how Contacts behave in specific situations.
@Mock
ContactsDatabase db;
@Test
public void injectingMock() {
Contacts contacts = new Contacts(db);
when(db.getName(0)).thenReturn("JS");
when(db.getPhoneNumber(0)).thenReturn("100-1234-5678");
assertEquals("{ JS, 100-1234-5678 }", contacts.getUserInfo(0));
}
Injection of Mock objects with @InjectMocks
The above example created a constructor called ‘Contacts(ContactsDatabase db)’ to inject a Mock object into Contacts.
@InjectMocks
allows you to inject Mock objects without creating a constructor.
First, delete the Contacts(ContactsDatabase db)
constructor as follows.
public class Contacts {
private ContactsDatabase db;
public Contacts() {
db = new ContactsDatabase();
}
....
}
If you define Contacts as a Member variable with @InjectMocks
as follows, objects created with @Mock
are injected into Contacts.
@Mock
ContactsDatabase db;
@InjectMocks
Contacts contacts = new Contacts();
@Test
public void injectingMock() {
when(db.getName(0)).thenReturn("JS");
when(db.getPhoneNumber(0)).thenReturn("100-1234-5678");
assertEquals("{ JS, 100-1234-5678 }", contacts.getUserInfo(0));
}
If you run it, you can see that it works the same as the example above.
Injection of Mock object into Spy object
You cannot use @InjectMocks
to inject mocks into Spy objects.
When creating an object, you must use a method of passing a mock to the constructor as an argument.
You can create a spy object by passing the Contacts object injected with the Mock object of ContactsDatabase as an argument to spy()
as follows.
@Mock
ContactsDatabase db;
@Test
public void injectingMockIntoSpy() {
Contacts contacts = spy(new Contacts(db));
doReturn("JS").when(db).getName(0);
doReturn("100-1234-5678").when(db).getPhoneNumber(0);
assertEquals("{ JS, 100-1234-5678 }", contacts.getUserInfo(0));
}
Clean up
We learned how to use @Mock
, @Spy
, @Captor
, and @InjectMocks
.
This annotation allows you to write test code with less code.
Related Posts
- Java - Remove items from List while iterating
- Java - How to find key by value in HashMap
- Java - Update the value of a key in HashMap
- Java - How to put quotes in a string
- Java - How to put a comma (,) after every 3 digits
- BiConsumer example in Java 8
- Java 8 - Consumer example
- Java 8 - BinaryOperator example
- Java 8 - BiPredicate Example
- Java 8 - Predicate example
- Java 8 - Convert Stream to List
- Java 8 - BiFunction example
- Java 8 - Function example
- Java - Convert List to Map
- Exception testing in JUnit
- Hamcrest Collections Matcher
- Hamcrest equalTo () Matcher
- AAA pattern of unit test (Arrange/Act/Assert)
- Hamcrest Text Matcher
- Hamcrest Custom Matcher
- Why Junit uses Hamcrest
- Java - ForkJoinPool
- Java - How to use Futures
- Java - Simple HashTable implementation
- Java - Create a file in a specific path
- Java - Mockito의 @Mock, @Spy, @Captor, @InjectMocks
- Java - How to write test code using Mockito
- Java - Synchronized block
- Java - How to decompile a ".class" file into a Java file (jd-cli decompiler)
- Java - How to generate a random number
- Java - Calculate powers, Math.pow()
- Java - Calculate the square root, Math.sqrt()
- Java - How to compare String (==, equals, compare)
- Java - Calculate String Length
- Java - case conversion & comparison insensitive (toUpperCase, toLowerCase, equalsIgnoreCase)