I am unsure on how to mock an enum singleton class.
public enum SingletonObject{ INSTANCE; private int num; protected setNum(int num) { this.num = num; } public int getNum() { return num; }
I'd like to stub getNum() in the above example, but I can't figure out how to mock the actual SingletonObject class. I thought using Powermock to prepare the test would help since enums are inherently final.
//... rest of test code @Test public void test() { PowerMockito.mock(SingletonObject.class); when(SingletonObject.INSTANCE.getNum()).thenReturn(1); //does not work }
This is using PowerMockMockito 1.4.10 and Mockito 1.8.5.
If you are using Mockito 3.4. 0+, you may mock a singleton like the following, without PowerMock or other dependencies.
It is possible, but this is not recommended, it would be better to refactor the code.
Of course you can – and probably will – use Mockito and PowerMock in the same JUnit test at some point of time.
By default, the Enum instance is thread-safe, and you don't need to worry about double-checked locking. In summary, the Singleton pattern is the best way to create Singleton in Java 5 world, given the Serialization and thread-safety guaranteed and with some line of code enum.
If you want to stub out what INSTANCE returns, you can do it but it's kind of nasty (using reflection & bytecode manipulation). I created & tested a simple project with three classes using the PowerMock 1.4.12 / Mockito 1.9.0. All classes were in the same package.
public enum SingletonObject { INSTANCE; private int num; protected void setNum(int num) { this.num = num; } public int getNum() { return num; } }
public class SingletonConsumer { public String consumeSingletonObject() { return String.valueOf(SingletonObject.INSTANCE.getNum()); } }
import static org.junit.Assert.*; import static org.powermock.api.mockito.PowerMockito.*; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import org.powermock.reflect.Whitebox; @RunWith(PowerMockRunner.class) @PrepareForTest({SingletonObject.class}) public class SingletonConsumerTest { @Test public void testConsumeSingletonObject() throws Exception { SingletonObject mockInstance = mock(SingletonObject.class); Whitebox.setInternalState(SingletonObject.class, "INSTANCE", mockInstance); when(mockInstance.getNum()).thenReturn(42); assertEquals("42", new SingletonConsumer().consumeSingletonObject()); } }
The call to the Whitebox.setInternalState
replaces INSTANCE
with a mock object that you can manipulate within your test.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With