簡體   English   中英

如何模擬Final類並覆蓋代碼

[英]How to mock Final classes and have code coverage

我無法找到解決JUnit問題的解決方案,因此我嘗試將其簡化為最大程度,因此希望它易於理解。

基本上,我正在嘗試測試此類:

public class PB {
    public int startProcessBuilder() {
        int status = 1;
        try {
            ProcessBuilder pb = new ProcessBuilder("java", "-jar", ".....");
            pb.directory(new File("/directory"));
            Process process = pb.start();
            status = process.waitFor();
        } catch (IOException | InterruptedException e) {
            System.out.println(e.getMessage());
        }
        return status;
    }
}

所以我想出了這個測試:

@RunWith(PowerMockRunner.class)
@PrepareForTest({ ProcessBuilder.class, PB.class })
public class PBTest {

    private PB spyInstance = Mockito.spy(PB.class);
    private ProcessBuilder processBuilderMock = PowerMockito.mock(ProcessBuilder.class);
    private Process processMock = Mockito.mock(Process.class);

    @Before
    public void initialize() throws Exception {
        PowerMockito.whenNew(ProcessBuilder.class).withParameterTypes(String[].class).withArguments(anyVararg())
                .thenReturn(processBuilderMock);
        PowerMockito.doReturn(processMock).when(processBuilderMock).start();
    }

    @Test
    public void testStartProcessBuilder() throws Exception {
        assertThat(spyInstance.startProcessBuilder(), is(0));
    }
}

我知道我的測試運行成功,但是在我所工作的公司中,我們正在使用jacoco和eclemma來顯示代碼覆蓋率,並且這是一個已知問題,如果我們正在測試的類,則所有代碼都顯示為0%覆蓋率在@PrepareForTest批注中。

因此,有一段時間,我們正在使用MockitoJUnitRunner( http://www.notonlyanecmplace.com/make-eclemma-test-coverage-work-with-powermock/ )解決一個已知的解決方案

@RunWith(MockitoJUnitRunner.class)
@PrepareForTest({ ProcessBuilder.class, PB.class })
public class PBTest {

    private PB spyInstance = Mockito.spy(PB.class);
    private ProcessBuilder processBuilderMock = PowerMockito.mock(ProcessBuilder.class);
    private Process processMock = Mockito.mock(Process.class);

    @Rule
    public PowerMockRule rule = new PowerMockRule();

    static {
        PowerMockAgent.initializeIfNeeded();
    }

    @Before
    public void initialize() throws Exception {
        PowerMockito.whenNew(ProcessBuilder.class).withParameterTypes(String[].class).withArguments(anyVararg())
                .thenReturn(processBuilderMock);
        PowerMockito.doReturn(processMock).when(processBuilderMock).start();
    }

    @Test
    public void testStartProcessBuilder() throws Exception {
        assertThat(spyInstance.startProcessBuilder(), is(0));
    }
}

現在出現了真正的問題:當我嘗試運行測試時,出現此異常:org.mockito.exceptions.misusing.NotAMockException:傳遞給when()的參數不是模擬的! 並顯示以下行:

PowerMockito.doReturn(processMock).when(processBuilderMock).start();

是的,很明顯,processBuilderMock不是模擬而是Powermock,所以我嘗試替換了這兩行

private ProcessBuilder processBuilderMock = PowerMockito.mock(ProcessBuilder.class);

PowerMockito.doReturn(processMock).when(processBuilderMock).start();

這樣 :

private ProcessBuilder processBuilderMock = Mockito.mock(ProcessBuilder.class);

PowerMockito.doReturn(processMock).when(processBuilderMock).start();

但是,然后當然: Cannot mock/spy class java.lang.ProcessBuilder... because it is a final class (可能是為什么我最初使用PowerMock的原因)

我有什么選擇?

您可以將PB類設計為易於測試。 一種方法是提取ProcessBuilder參數:

public class PB {
  public int startProcessBuilder(String... args) {
    try {
      ProcessBuilder pb = new ProcessBuilder(args);

在測試的后面,您可以使用一個小的“ Hello World”測試JAR:

new PB().startProcessBuilder("java", "-jar", "path-to-test-jar");

或使用標准的echo命令,無論使用什么操作系統,該命令都應具有相同的語法:

new PB().startProcessBuilder("echo", "Hello", "World");

您不需要模擬任何東西,而實際上使用模擬JAR調用模擬Java進程。

您要增加覆蓋面會遇到很多麻煩,這一事實表明您當前的開發過程值得懷疑。 覆蓋范圍本身並不是目標,它是使您對代碼充滿信心的度量標准。 如果您必須避免使用@PrepareForTest來增強效果,那有什么意義呢?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM