如何使用Mockito / Powermock模拟枚举单例类?

时间:2013-04-11 00:51:25

标签: java enums singleton mockito powermock

我不确定如何模拟枚举单例类。

public enum SingletonObject{
  INSTANCE;
  private int num;

  protected setNum(int num) {
    this.num = num;
  }

  public int getNum() {
    return num;
  }

我想在上面的例子中存根getNum(),但是我无法弄清楚如何模拟实际的SingletonObject类。我认为使用Powermock准备测试会有所帮助,因为枚举本身就是最终的。

//... rest of test code
@Test
public void test() {
  PowerMockito.mock(SingletonObject.class);
  when(SingletonObject.INSTANCE.getNum()).thenReturn(1); //does not work
}

这是使用PowerMockMockito 1.4.10和Mockito 1.8.5。

4 个答案:

答案 0 :(得分:23)

如果你想要删除INSTANCE返回的内容,你可以这样做,但它有点讨厌(使用反射和字节码操作)。我创造了&使用PowerMock 1.4.12 / Mockito 1.9.0测试了一个包含三个类的简单项目。所有课程都在同一个课程中。

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());
    }
}

Whitebox.setInternalState的调用用您可以在测试中操作的模拟对象替换INSTANCE

答案 1 :(得分:0)

与您要模拟的方法具有接口

public interface SingletonInterface {
  int getNum();
}

让枚举实现接口

public enum SingletonObject implements SingletonInterface {
    INSTANCE;
    private int num;

    protected void setNum(int num) {
        this.num = num;
    }

    @Override
    public int getNum() {
        return num;
    }
}

模拟界面

@Test
public void test() {
  SingletonInterface singleton = Mockito.mock(SingletonInterface.class);
  when(singleton.getNum()).thenReturn(1); //does work
}

答案 2 :(得分:0)

除了以上Matt Lachman的答案外,还在SingleTonConsumerTest.class

中创建对象工厂以进行电源模拟
@ObjectFactory
public IObjectFactory getObjectFactory() {
    return new org.powermock.modules.testng.PowerMockObjectFactory();
}

这将消除Mockito cannot mock/spy following: - final classes - anonymous classes - primitive types错误。

答案 3 :(得分:0)

我不确定这是否是最好的方法,但就我而言,到目前为止它没有问题。我正在使用 mockito-core 和 mockito-inline (3.11.0),我在间谍的帮助下嘲笑我的单身人士。您的班级示例:

SingletonObject so = SingletonObject.INSTANCE;
private SingletonObject spySo = Mockito.spy(so);

@Before
public void setUp() {
    Mockito.doReturn(10).when(spySo).getNum();
}

@Test
public void simpleTest() {
    assertThat(spySo.getNum(), is(10));
}