[JAVA] Proper use of Mockito and PowerMock

I tried to organize the proper use of Mockito and PowerMock when mocking various methods when testing with JUnit with Spring Boot.

Settings required for testing

build.gradle


dependencies {
    compile("org.springframework.boot:spring-boot-starter-web")
    testCompile('org.springframework.boot:spring-boot-starter-test')
    testCompile group: 'org.powermock', name: 'powermock-api-mockito', version: '1.6.6'
    testCompile group: 'org.powermock', name: 'powermock-module-junit4', version: '1.6.6'
}

Just put spring-boot-starter-test and you can use the following two libraries. The version is ** spring-boot-gradle-plugin: 1.5.2.RELEASE **.

Add a setting to use the power mock that will be used later.


Class used for explanation

Class to be tested

TestTargetClass.java


@Component
public class TestTargetClass {
  @Autowired
  private TestSubClass testSubClass;

  private String private_method() {
    return "private_method called " + private_sub();
  }

  private String private_sub() {
    return "private_sub";
  }

  public String public_method() {
    return "public_method called " + public_sub();
  }

  public String public_sub() {
    return "public_sub";
  }

  public String public_method_call_private_method() {
    return "public_method called " + private_sub();
  }

  public static String static_method() {
    return "static_method";
  }

  public String public_subclass_public_method() {
    return "public_subclass_method called " + testSubClass.sub_public_method();
  }

  public String public_subclass_private_method() {
    return "public_subclass_method called " + testSubClass.sub_public_method_call_private_method();
  }
}

Subclass to be tested (subclass DI from parent class)

TestSubClass.java


@Component
public class TestSubClass {

  public String public_field = "public_field";
  private String private_field = "private_field";

  private String sub_private_method() {
    return "subclass_private_method has " + private_field;
  }

  public String sub_public_method() {
    return "subclass_public_method has " + public_field;
  }

  public String sub_public_method_call_private_method() {
    return "subclass_public_method called " + sub_private_method();
  }
}

First from the basic test

You can use Mockito for the test class like this.

RealTest.java


@RunWith(SpringRunner.class)
@SpringBootTest
public class RealTest {
  @Autowired
  private TestTargetClass instance;

  @Test
public void test method() {
    .....
  }
}

Testing the actual behavior of public methods

Needless to write, here is the test code

  @Test
public void can be tested by calling public methods() {
    assertThat(public_method(), is("public_method called public_sub"));
  }

Testing the actual behavior of private methods

OK if you use setAccessible with reflection

  @Test
public void can be tested by calling private methods() throws Exception {
    Method method = TestTargetClass.class.getDeclaredMethod("private_method");
    method.setAccessible(true);
    assertThat((String) method.invoke(instance), is("private_method called private_sub"));
  }

Testing the actual behavior of static methods

Needless to write, here is the test code

  @Test
can be tested by calling public void static methods() {
    assertThat(TestTargetClass.static_method(), is("static_method"));
  }

Here is the test using the mock of the main subject.


Tests that can only be done with Mockito

When mocking public methods

In such cases, use Mockito.mock ().

  @Test
public void can mock public methods() {
    TestTargetClass mockInstance = mock(TestTargetClass.class);
    when(mockInstance.public_method()).thenReturn("mocked_public_method");
    assertThat(mockInstance.public_method(), is("mocked_public_method"));
  }

When mocking a sub public method called from a public method

I want the methods other than the mocking method public_sub () to work as implemented, so use Mockito.spy () in such cases.

  @Test
public void Sub methods called by public methods can be mocked with Spy() {
    TestTargetClass mockInstance = spy(new TestTargetClass());
    when(mockInstance.public_sub()).thenReturn("mocked_public_sub");
    assertThat(mockInstance.public_method(), is("public_method called mocked_public_sub"));
  }

Tests that can be done with PowerMock

The test class when using PowerMock looks like this

@RunWith(PowerMockRunner.class)
@PrepareForTest({TestTargetClass.class})
public class PowerMockTest {
  @Test
public void test method() {
    .....
  }
}

Private method mock

Use PowerMockito.mock () and PowerMockito.when (). Also, to specify a private method, use MemberMatcher.method () to reflect.

  @Test
public void private methods can be mocked with PowerMockito() throws Exception {
    TestTargetClass mockInstance = PowerMockito.mock(TestTargetClass.class);
    PowerMockito.when(mockInstance, MemberMatcher.method(TestTargetClass.class, "private_method"))
                .withNoArguments().thenReturn("mocked_private_method");

    //Use reflection to access private methods
    Method method = TestTargetClass.class.getDeclaredMethod("private_method");
    method.setAccessible(true);

    assertThat((String) method.invoke(mockInstance), is("mocked_private_method"));
  }

Static method mock

Use PowerMockito.mockStatic () and PowerMockito.when ().


  @Test
public void static methods can be mocked with PowerMockito()() {
    PowerMockito.mockStatic(TestTargetClass.class);
    PowerMockito.when(TestTargetClass.static_method()).thenReturn("mocked_static_method");
    assertThat(TestTargetClass.static_method(), is("mocked_static_method"));
  }

When mocking a sub private method called from a public method

Since we want methods other than the mocking method private_sub () to work as implemented, use PowerMockito.spy () and PowerMockito.when () in such cases. Also, to specify a private method, use MemberMatcher.method () to reflect.

  @Test
public void Sub-private methods called from public methods can be mocked with spy() throws Exception {
    TestTargetClass mockInstance = PowerMockito.spy(new TestTargetClass());
    PowerMockito.when(mockInstance, MemberMatcher.method(TestTargetClass.class, "private_sub"))
                .withNoArguments().thenReturn("mocked_private_sub");

    assertThat(mockInstance.public_method_call_private_method(),
        is("public_method called mocked_private_sub"));
  }

When mocking a class that is DI in the class

It is assumed that the service class that is DI in the controller class is mocked. PowerMock is used at this time as well. DI the target class of @ Autowired specified in the class specified by @InjectMocks in the @SpringBootTest annotation. The target class of @ Autowired isPowerMockito.spy ()as a class variable.


The test class looks like this

@RunWith(PowerMockRunner.class)
//PowerMock target class
@PrepareForTest({TestSubClass.class})
@SpringBootTest
public class PowerMockSubclassTest {
  @InjectMocks
  private TestTargetClass instance;
  private TestSubClass testSubClass = PowerMockito.spy(new TestSubClass());

  @Test
public void test method() {
    .....
  }
}

It seems that you can not mock even if you do the following instead of the class variable. ... Perhaps Please comment if there is any good way.

  @Test
public void test method() {
     TestSubClass testSubClass = PowerMockito.spy(new TestSubClass());
  }

Mock public methods in subclasses

Since it is actually a public method, the part where the subclass is declared in the test class is

private TestSubClass testSubClass = PowerMockito.mock(TestSubClass.class);

However, it cannot be used together with the one using spy () in the same source file, so unify it with spy (). Use PowerMockito.when ().

  @Test
public void You can mock public methods of subclasses() {
    PowerMockito.when(testSubClass.sub_public_method()).thenReturn("mocked_subclass_public_method");
    assertThat(instance.public_subclass_public_method(),
        is("public_subclass_method called mocked_subclass_public_method"));
  }

Mock a subclass's private method

Use PowerMockito.when (). Also, to specify a private method, use MemberMatcher.method () to reflect.

  @Test
public void Can mock private methods of subclasses() throws Exception {
    PowerMockito.when(testSubClass, MemberMatcher.method(TestSubClass.class, "sub_private_method"))
        .withNoArguments().thenReturn("mocked_sub_private_method");

    assertThat(instance.public_subclass_private_method(), is(
        "public_subclass_method called subclass_public_method called mocked_sub_private_method"));
  }

Mock public fields in subclasses

Use Whitebox.setInternalState () to mock a subclass field.

  @Test
public void You can mock public fields in subclasses() {
    Whitebox.setInternalState(testSubClass, "public_field", "mocked_public_field");
    assertThat(instance.public_subclass_public_method(),
        is("public_subclass_method called subclass_public_method has mocked_public_field"));
  }

Mock a subclass's private field

Use Whitebox.setInternalState () to mock a subclass field. Same as setting it in the public field.

  @Test
public void Can mock private fields in subclasses() {
    Whitebox.setInternalState(testSubClass, "private_field", "mocked_private_field");
    assertThat(instance.public_subclass_private_method(), is(
        "public_subclass_method called subclass_public_method called subclass_private_method has mocked_private_field"));
  }

It's a long sentence, but that's it.

Recommended Posts

Proper use of Mockito and PowerMock
Proper use of redirect_to and render
Proper use of interface and abstract class
Criteria for proper use of render and redirect_to
[Java8] Proper use of Comparable and Comparator in terms of employee sorting
(Determine in 1 minute) About the proper use of empty ?, blank? And present?
Do you use the for statement after all? Do you use a while statement? Proper use of for statement and while statement
Use of Date class
Mockito + PowerMock cheat sheet
Use of Japanese fonts and external characters in JasperReport
Minimal usage of Mockito
Until the use of Spring Data and JPA Part 2
Until the use of Spring Data and JPA Part 1
Use of Abstract Class and Interface properly in Java
Handling of date and time in Ruby. Use Date and Time properly.
behavior of didSet and willSet
Overview of Docker and containers
Background and mechanism of Fabric-loader
Summary of FileInputStream and BufferedInputStream
Combination of search and each_with_index
Judgment of JSONArray and JSONObject
Mock and spy on PowerMock
Use @ValueSource of ParametrisedTest of JUnit5
Operator of remainder and exponentiation (exponentiation)
Advantages and disadvantages of Java
[Docker-compose] How to use unnamed and named volumes of volumes. Bind mount
Build a container version of Minecraft server and use https-enabled Dynmap