Mock private methods in PowerMock

table of contents

  1. Procedure for building an environment for using PowerMock
  2. Mock and Spy in PowerMock
  3. Mock static methods with PowerMock
  4. Mock the constructor with PowerMock
  5. Mock private methods with PowerMock ← Now here
  6. Try using PowerMock's WhiteBox
  7. Disable static initializer in PowerMock

Overview

With PowerMock, you can set the return value of the private method to an arbitrary value or return an exception.

It is assumed that the private method of the Utility class (mocking class) called from the UseUtility class (test target class) is mocked.

Tested class

This is the class to be tested that is called from JUnit.

I am calling the public method of the Utility class inside the method.

UseUtility.java


public class UseUtility {

	public String getMessage(String id) throws Exception {

		Utility utility = new Utility();

		Map<String, String> userInfo = utility.getUserInfo(id);

		String message = id + ":" + userInfo.get(id);

		return message;
	}
}

Mocking class

I'm calling a private method inside a public method and want to mock it.

Utility.java


public class Utility {

	public Utility() {
		//abridgement
	}

	public Map<String, String> getUserInfo(String id) throws Exception {

		this.connectDatabase("env");

		Map<String, String> userInfo = new HashMap<>();
		userInfo.put(id, this.getName(id));

		return userInfo;
	}

	private String getName(String id) throws Exception {
		//Unimplemented assumption
		return "";
	}

	private void connectDatabase(String env) {
		//Assumption of processing that you do not want to execute
	}
}

Test class

JUnit that calls the class under test.

To use PowerMock with JUnit, specify PowerMockRunner for @RunWith.

Note that in @PrepareForTest, you need to write not only the class to be mocked, but also the class that calls the constructor.

UseUtilityTest.java


@RunWith(PowerMockRunner.class)
@PrepareForTest({ Utility.class, UseUtility.class })
public class UseUtilityTest {
    //abridgement
}

Example of use

doReturn Set the return value in the private method.

To mock it, use when (mock object, private method name string, private method argument, ...).

@Test
public void test_doReturn() throws Exception {
	//Preparation
	String id = "0001";
	String expected = "0001:TestUser";

	//Spy
	Utility spy = PowerMockito.spy(new Utility());
	//Set the instance to be returned in the constructor
	PowerMockito.whenNew(Utility.class).withNoArguments().thenReturn(spy);
	//Set the return value of the private method of the spyed class
	PowerMockito.doReturn("TestUser").when(spy, "getName", anyString());

	//Run
	UseUtility obj = new UseUtility();
	String actual = obj.getMessage(id);

	//Check the result
	assertEquals(expected, actual);
}

doThrow Throw an exception with a private method.

@Test(expected = Exception.class)
public void test_doThrow() throws Exception {
	//Preparation
	String id = "0001";
	Exception expected_exception = new Exception("error!");
	
	//Spy
	Utility spy = PowerMockito.spy(new Utility());
	//Set the instance to be returned in the constructor
	PowerMockito.whenNew(Utility.class).withNoArguments().thenReturn(spy);
	//Set exception to return in private method of spy class
	PowerMockito.doThrow(expected_exception).when(spy, "getName", anyString());

	//Run
	UseUtility obj = new UseUtility();
	obj.getMessage(id);
}

doCallRealMethod Call the real method without returning value or exception setting to private method.

@Test
public void test_doCallRealMethod() throws Exception {
	//Preparation
	String id = "0001";
	String expected = "0001:";

	//Spy
	Utility spy = PowerMockito.spy(new Utility());
	//Set the instance to be returned in the constructor
	PowerMockito.whenNew(Utility.class).withNoArguments().thenReturn(spy);
	//Set to call the real thing in the private method of the spy class
	PowerMockito.doCallRealMethod().when(spy, "getName", anyString());

	//Run
	UseUtility obj = new UseUtility();
	String actual = obj.getMessage(id);

	//Check the result
	assertEquals(expected, actual);
}

doNothing Use when you don't want to do anything with a private method.

@Test
public void test_doNothing() throws Exception {
	//Preparation
	String id = "0001";
	String expected = "0001:";

	//Spy
	Utility spy = PowerMockito.spy(new Utility());
	//Set the instance to be returned in the constructor
	PowerMockito.whenNew(Utility.class).withNoArguments().thenReturn(spy);
	//Set the private method of the spy class to do nothing
	PowerMockito.doNothing().when(spy, "connectDatabase", anyString());

	//Run
	UseUtility obj = new UseUtility();
	String actual = obj.getMessage(id);

	//Check the result
	assertEquals(expected, actual);
}

thenReturn Set the return value in the private method.

@Test
public void test_thenReturn() throws Exception {
	//Preparation
	String id = "0001";
	String expected = "0001:TestUser";

	//Spy
	Utility spy = PowerMockito.spy(new Utility());
	//Set the instance to be returned in the constructor
	PowerMockito.whenNew(Utility.class).withNoArguments().thenReturn(spy);
	//Set the return value of the private method of the spyed class
	PowerMockito.when(spy, "getName", anyString()).thenReturn("TestUser");

	//Run
	UseUtility obj = new UseUtility();
	String actual = obj.getMessage(id);

	//Check the result
	assertEquals(expected, actual);
}

thenThrow Throw an exception with a private method.

@Test(expected = Exception.class)
public void test_thenThrow() throws Exception {
	//Preparation
	String id = "0001";
	Exception expected_exception = new Exception("error!");

	//Spy
	Utility spy = PowerMockito.spy(new Utility());
	//Set the instance to be returned in the constructor
	PowerMockito.whenNew(Utility.class).withNoArguments().thenReturn(spy);
	//Set exception to return in private method of spy class
	PowerMockito.when(spy, "getName", anyString()).thenThrow(expected_exception);

	//Run
	UseUtility obj = new UseUtility();
	obj.getMessage(id);
}

thenCallRealMethod Call the real method without returning value or exception setting to private method.

@Test
public void test_thenCallRealMethod() throws Exception {
	//Preparation
	String id = "0001";
	String expected = "0001:";

	//Spy
	Utility spy = PowerMockito.spy(new Utility());
	//Set the instance to be returned in the constructor
	PowerMockito.whenNew(Utility.class).withNoArguments().thenReturn(spy);
	//Set to call the real thing in the private method of the spy class
	PowerMockito.when(spy, "getName", anyString()).thenCallRealMethod();

	//Run
	UseUtility obj = new UseUtility();
	String actual = obj.getMessage(id);

	//Check the result
	assertEquals(expected, actual);
}

Private method validation

PowerMock provides verifyPrivate for validating mocked private methods.

You can use Mockito's times, atLeast, asLeastOnce, etc. to verify the number of calls.

verifyPrivate ([mock object]) is synonymous with verifyPrivate ([mock object], times (1)).

//Confirm that it was called once
PowerMockito.verifyPrivate(spy).invoke("getName", anyString());

Recommended Posts

Mock private methods in PowerMock
Test private methods in JUnit
Test private methods in JUnit
Mock static methods in Mockito 3.4
Mock Enums with PowerMock
How to mock a super method call in PowerMock
Check Java9 Interface private methods
Mock and spy on PowerMock
Mock the constructor with PowerMock
Things to keep in mind when testing private methods in JUnit
Disable static initializer in PowerMock
Frequently used methods in Active Record
[Java] Test private methods with JUnit
Mock only some methods with Spock
Ruby methods often used in Rails