簡體   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