Mock Enums with PowerMock

Overview

With PowerMock, you can mock the Enum class and write test code in JUnit.

environment

version
Java 8
JUnit 4.12
Mockito 2.23
PowerMock 2.0.2

List of libraries used

Sample code

Mocking target class

public enum SampleEnum {
	
	ELEM1("val1"),
	ELEM2("val2");
	
	private String val;
	
	private SampleEnum(String val) {
		this.val = val;
	}
	
	public String getVal() {
		return this.val;
	}
}

Test class

@RunWith(PowerMockRunner.class)
@PrepareForTest(SampleEnum.class)
public class SampleEnumTest {

	@Test
	public void test() throws Exception {

		//Expected value
		String expected_elem1 = "test";
		String expected_elem2 = "val2";

		//Mock an Enum
		SampleEnum mocked = Mockito.mock(SampleEnum.class);

		//Set the return value in the method and stub
		Mockito.when(mocked.getVal()).thenReturn(expected_elem1);
		//If not stubbed
		// Mockito.when(mocked.getVal()).thenCallRealMethod();

		//Set a mocked object in the element of Enum
		Whitebox.setInternalState(SampleEnum.class, "ELEM1", mocked);

		//Run
		String actual_elem1 = SampleEnum.ELEM1.getVal(); // "test"Returns
		String actual_elem2 = SampleEnum.ELEM2.getVal(); // "val2"Returns

		//Check the result
		assertEquals(expected_elem1, actual_elem1);
		assertEquals(expected_elem2, actual_elem2);
	}
}

Point ①

In fact, the Enum mocking itself doesn't use the PowerMock library. It can be mocked with the Mockito library, like Mockito.mock (SampleEnum.class). (PowerMockito.mock, PowerMockito.when can also be used instead of Mockito.)

The point is to specify PowerMockRunnner.class in @Runwith and describe the Enum class you want to mock in @PrepareForTest.

After that, you can set the return value with thenReturn (), or call the actual method with thenCallRealMethod () without stubbing.

If you try to comment out @Runwith and @PrepareForTest and execute it, the following error log will be output.

org.mockito.exceptions.base.MockitoException: 
Cannot mock/spy class jp.co.sample_powermock.enumtest.SampleEnum
Mockito cannot mock/spy because :
 - final class

The JUnit4 test runner doesn't seem to support mocking the Enum class.

Point ②

Each Enum constant can be thought of as an instance of an Enum. By injecting a mocked Enum object into each of these instances, Enum mocking is established.

The sample code uses the PowerMock library Whitebox.setInternalState () to inject a mock object into the Enum element "ELEM1".

As a result, SampleEnum.ELEM1 behaves as the set mock object, and SampleEnum.ELEM2 behaves as it is.

You can set mock objects in java.lang.reflect without using Whitebox, but I think using Whitebox keeps your code simpler.

Recommended Posts

Mock Enums with PowerMock
Mock static methods with PowerMock
Mock the constructor with PowerMock
How to mock each case with PowerMock + Mockito1x
Mock and spy on PowerMock
MOCK constructors of other classes with Spring MVC + PowerMock + Junit
Mock only some methods with Spock
Item 38: Emulate extensible enums with interfaces
Use FacesContext as a Mock with PowerMockito