繁体   English   中英

如何模拟由静态方法创建的实例?

[英]How to mock an instance created by a static method?

我正在测试看起来像这样的遗留代码。

class Converter {
  static String convert() {
    SubConverter.subConvert();
  }
}
class SubConverter {
  static String subConvert() {
    Generator generator = new Generator();
    return generator.generate();
  }
}

我的目标是测试Converter.convert ,模拟generator.generate()

测试类如下所示:

import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

class ConverterTest {

  @Mock
  Generator generatorMock;
  
  @Test
  public void convertTest(){
    MockitoAnnotations.openMocks(this);
    Mockito.when(generatorMock.generate()).thenReturn("123");
    Converter.convert();
    // some assertions
  }
}

使用Generator.generate()的实际实现而不是模拟。

我试过了:

import org.mockito.InjectMocks;

@InjectMocks
Converter converterWithMock;

,测试converterWithMock.convert() ,结果相同。

我已经尝试过使用 PowerMockito,但我无法让它工作(也许我以错误的方式使用它)。

这样做的正确方法是什么?

使用junit-jupiter 5.8.2mockito 4.3.1

您需要模拟Generator类的构造函数。


解决方案 1:使用 Mockito(主要优先)
Mockito 从 3.5 版本开始支持模拟构造。 文档
mockito-inline添加到您的依赖项中。 它提供了在构造函数调用上生成模拟的能力。

        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-inline</artifactId>
            <version>4.3.1</version>
            <scope>test</scope>
        </dependency>

模拟构造函数。

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.MockedConstruction;
import org.mockito.Mockito;

import static org.mockito.Mockito.*;

class ConverterTest {
    @Test
    public void convertTest(){
        //create mock for Generator class constructor
        try (MockedConstruction<Generator> mockedGenerator = Mockito.mockConstruction(Generator.class,
                (mock, context) -> {
                    when(mock.generate()).thenReturn("123");
                })) {

            //execute Converter class under the test
            String result = Converter.convert();
            
            //ensure that constructor was executed
            Assertions.assertFalse(mockedGenerator.constructed().isEmpty());
            //ensure the generate method was executed
            verify(mockedGenerator.constructed().get(0), times(1)).generate();
            //verify return value
            Assertions.assertEquals("123", result);
        }
    }
}

解决方案 2:使用 PoserMock
PowerMock不支持 JUnit 5 ,只有 Junit 4。
通过 PowerMock 模拟构造函数的示例

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(SubConverter.class)
public class ConverterTest {

    @Mock
    Generator generatorMock; //create Mock

    @Test
    public void convertTest() throws Exception {
        //configure Mock
        Mockito.when(generatorMock.generate()).thenReturn("123");
        //return mock when constructor is executing
        PowerMockito.whenNew(Generator.class).withNoArguments().thenReturn(generatorMock);

        //perform Converter under the test 
        String result = Converter.convert();

        //check return value
        Assert.assertEquals("123", result);
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM