Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock an enum singleton class using Mockito/Powermock?

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.

like image 846
Sonwright Gomez Avatar asked Apr 11 '13 00:04

Sonwright Gomez


People also ask

Can Mockito mock Singleton?

If you are using Mockito 3.4. 0+, you may mock a singleton like the following, without PowerMock or other dependencies.

Can enum class be mocked?

It is possible, but this is not recommended, it would be better to refactor the code.

Can Mockito and PowerMock be used together?

Of course you can – and probably will – use Mockito and PowerMock in the same JUnit test at some point of time.

Is enum singleton thread safe?

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.


1 Answers

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.

SingletonObject.java

public enum SingletonObject {     INSTANCE;     private int num;      protected void setNum(int num) {         this.num = num;     }      public int getNum() {         return num;     } } 

SingletonConsumer.java

public class SingletonConsumer {     public String consumeSingletonObject() {         return String.valueOf(SingletonObject.INSTANCE.getNum());     } } 

SingletonConsumerTest.java

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.

like image 69
Matt Lachman Avatar answered Sep 24 '22 07:09

Matt Lachman