如何使用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
}

这是使用PowerMockito 1.4.10和Mockito 1.8.5。

如果你想截取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());
    }
}

单身消费者测试.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替换为可以在测试中操作的mock对象。

有一个与模拟的方法的接口

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
}

除了上面的Matt Lachman答案之外,还为SingleTonConsumerTest.class 中的power mock创建了一个对象工厂

@ObjectFactory
public IObjectFactory getObjectFactory() {
    return new org.powermock.modules.testng.PowerMockObjectFactory();
}

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

我不确定这是否是最好的方法,但就我的情况而言,到目前为止,它运行得很顺利。我使用mockito核心和mockito内联(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));
}

Mockito文档在enum用例中不显式:

  • 模拟最终类型、枚举和最终方法(自2.1.0起(

Powermock支持:

  • JUnit 4兼容

build.gradle(**也应与Maven一起使用(

    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
    testImplementation 'org.mockito:mockito-inline:4.0.0'
    testImplementation 'org.mockito:mockito-junit-jupiter:4.1.0'

根据可用的实验功能(Powermock+JUnit 5(,可以尝试:

    implementation group: 'org.powermock', name: 'powermock-module-junit5', version: '1.6.4'
    testImplementation 'org.powermock:powermock-mockito-release-full:1.6.4'

枚举:

public enum ConnectionFactory {
   INSTANCE;
   public Connection get() throws SQLException {
      //
      // Load url from configuration file  ('application.yml')
      //
      final var connection = DriverManager.getConnection(url);
      connection.setAutoCommit(false);
      return connection;
   }
}

可以使用以下方法:

class DatabaseUnitTests {
   private final ConnectionFactory connectionFactory = Mockito.spy(ConnectionFactory.INSTANCE);

   //Or
   @InjectMocks
   private final ConnectionFactory connectionFactory = Mockito.mock(ConnectionFactory.class);

   @Test
   void check_is_database_connection_is_OK(){
      Mockito.doReturn(mockedConnection()).when(connectionFactory).get();
       
      // Do something
   }

最新更新