[JAVA] Minimal usage of Mockito

Introduction

I decided to use ** JUnit + Mockito + PowerMock ** in the project I'm currently working on. In the first place, everything is unknown to me, who has never touched JUnit itself.

Even if you try gg with "** Mockito **", there are few articles that explain that people with zero knowledge can use it immediately. Or rather ** I don't have much Japanese! ** ** It's hard to understand without explanation in Japanese. ..

So, I'm writing this article for me who didn't know anything because I finally swallowed a little recently.

This time is ** Mockito ** edition.

In particular, I will write about the case where you want to mock a method of a class different from the class under test.

What Mockito can't do

First of all, there are many things that Mockito cannot do. It's not all-purpose, and the methods that can be mocked are limited. I can't mock it

-** private method ** -** static method ** -** protected method ** -** Instantiation (new) **

These are the above four types. (Perhaps) I also think that abstract classes couldn't be mocked. (Perhaps)

Otherwise, you can basically mock it with mockito (maybe). To mock the above four, you have to use PowerMock separately from Mockito.

Mock the class with the method you want to call

First, mock the class to call the mocked method. There are ** 2 types of mocking methods **. Only one of them is fine.

** ① Directly under the class @ Mock ** ** ② Use the mock () method **

Java



public class TestClass {
  //① Directly under the class@Declaring a mock instance in Mock
  @Mock
  private Entity entity; //This is a declaration only, no mock object is created
  
  @Test
  public void test001() {
     // ② mock()Use method
    Entity entity = mock(Entity.class); //This alone will create a mock object
  }
}

In case of ** ① **, it is necessary to initialize separately from this declaration. ** ② ** mock the class every time in the test class. It does not need to be initialized.

Mock initialization

In the case of @ Mock of ** ① **, the mock object has not been created yet, so it is necessary to ** initialize **.

Java



public class class() {
  // @Mock pattern
  @Mock
  private ResultEntity entity;
  
  @Before // @Annotate Before and execute each test method before execution.
  private void initMocks() {
    MockitoAnnotations.initMocks(this); //Initialization magic
  }
}

I think the ** ① ** method is effective when ** there are multiple test cases and the class you want to mock appears many times **.

Inject mock into the class under test

Use the @InjectMocks annotation to inject a mock into the tested class directly under the test class.

public class TestClass {
  @Mock
  Entity entity; //Mocked class

  @InjectMocks
  Human human; //Inject mock into the class under test
}

For the time being, it is possible to mock it and then test it. When getting coverage, ** it will not be 100% unless the instance of the class under test is called **, so if you want to set coverage to 100%

   @InjectMocks
  Human human = new Human();

It's okay to write like this.

Now that we have mocked the class, we will actually mock the method for each case below.

For public methods with a return value

public String etc. In this case, there are ~~ why ~~ ** 2 types ** of how to mock the method.

1.then method

Mockito.when(Mock instance).Method(Arbitrary argument).thenReturn(Any return value);
//It will return this return value when the method of the mocked class is called

The method is now mocked, and the method is not actually executed and is just a mock that returns an arbitrary return value.

By the way, the head Mockito. can be with or without it. Since PowerMock is written in the same way, ** if you use it at the same time, you need to use it properly **, so it will be easier to understand if you put it in your head.

2. do method

Mockito.doReturn(Any return value).when(Mock instance).Method(Arbitrary argument);
//I'll return this return value when the method of the mocked class is called

Both ① and ② behave exactly the same. As explained below, ** then method may not be able to handle it **, so it seems that there is no mistake if you unify with do method.

For public void methods with no return value

public void In this case, it can be described only by ** do method **.

Mockito.doNothing().when(Mock instance).Method(Arbitrary argument);
//It doesn't return anything, when a mock class method is called

There doesn't seem to be a method called thenNothing ().

Validate the arguments of the mocked method (ArgumentCaptor)

Since the method is mocked, there is no need to verify it, but I think it will be necessary to verify that the arguments passed to the mocked ** method are correct **.

You can use ʻArgument Captor` in such a case.

ArgumentCaptor<Mold>variable= ArgumentCaptor.forClass(Mold.class);
// forClass()Create a container (variable) of that type with a method

capture () method

If you pass the above variable as an argument when mocking the method, the argument actually passed will be captured and stored in the variable. At that time, add the capture () method.

Mockito.doReturn("Return value").when(class).Method(variable.capture());
// forClass()Create a container (variable) of that type with a method

The variable now contains the arguments passed in the actual source.

Acquisition of stored capture information

variable.getValue(); // ①
variable.getAllValues().get(index); // ②

By using either of these methods, you can get the value according to the type of the variable.

** ① ** If you want to verify only one argument, you can get the information stored by the getValue () method.

** ② ** ArgumentCaptor can be passed to ** arguments many times and can store as many results as there are arguments **. (Only for the same type.)

In that case, it is stored in the form of an array, so get all the values with the getAllValues () method. You can get the value of one of them with get (index).

Actually, if you reuse variables, it will be difficult to determine what number is in which argument, so basically ** declare the contents of ʻArgumentCaptor` as many as the number of arguments ** I think it's better to do it.

ArgumentCaptor<String> str = ArgumentCaptor.forClass(String.class);
Mockito.doReturn("Return value").when(Class).getStr(str.capture());
assertTaht(str.getValue(), is(Expected value of argument));

I think it will look like this.

Verify the number of mocked method calls

When you mock a method, it doesn't actually call that method, so you may need to ** verify that the mocked method is called properly **.

The verify () method is used at that time.

Mockito.verify(Mock instance, times(index)).Mock method(argument);

You can verify how many times the method has been called by passing the expected value as the mock instance as the first argument of the verify () method, the times () method as the second argument, and int as the argument.

Methods with no return value can be mocked only with verify ()

What do you mean

Mocking a method without a return value is as described in [For a public void method with no return value](# For a public void method with no return value).

If you want to verify the number of method calls, you don't have to do both doNothing () and verify (), you can do both at the same time with just ** verify (). ** **

Rather than doing it at the same time, it means that it has been mocked as a method with no return value at the time of ** verify () **.

The only caveat is that ** methods with a return value cannot be mocked with verify () **.

This is because verify () ** cannot mock the return value **.

// doNothing()Even if you do not mock with, this is ok
Mockito.verify(Mock instance, times(index)).Mock method();

By the way, in the above case + if you want to verify the argument

// doNothing()Even if you do not mock with, this is ok
Mockito.verify(Mock instance, times(index)).Mock method(variable.capture());

By doing so, the arguments can also be stored at this time.

Finally

If you remember these, I think you will be able to fight to some extent. I plan to write mocking of other methods of the same class and mocking of new in the future.

reference

[Java] How to drink Mockito (Introduction)

Recommended Posts

Minimal usage of Mockito
[Java] Mirage-Basic usage of SQL
Super basic usage of Eclipse
Validation of log messages using mockito
Basic usage of java Optional Part 1
Proper use of Mockito and PowerMock
[Rails] Differences and usage of each_with_index and each.with_index
From introduction to usage of byebug
[Specific usage of before_action] Rails refactoring
Basic usage of enums and code examples
Probably wrong usage of Colaboratory (try Kotlin)
[Ruby] Classification and usage of loops in Ruby
Introduction and usage explanation of Font Awesome