Runtime.getRuntime().exec jUnit test

5
我有一个类,其中的一些方法使用了以下代码:
Runtime.getRuntime().exec ...

例如:

public class MyClass {
    public void doSomething() {
        ...do something...
        Runtime.getRuntime().exec ...
        ...do something else
    }
}

很不幸,由于某些要求,我无法重构这个类。我想在这个类上创建jUnit测试,但我发现很难模拟Runtime类。

假设我想在Runtime进程返回X结果或Y结果的情况下测试“doSomething”方法。有没有什么办法可以模拟它?


当你说“无法重构”时,这意味着你甚至不能稍微修改它吗? - Nicolas Filotto
我可以稍微修改,但是我无法更改类以通过Runtime... - Panos
3个回答

4
您可以使用PowerMockitomockStatic方法来实现。
其思路是模拟静态的Runtime.getRuntime()方法,返回一个模拟的运行时对象,在此对象上您可以控制exec()的结果。
@RunWith(PowerMockRunner.class)
@PrepareForTest(Runtime.class)
public class TestClass {

  @Mock private Runtime mockRuntime;

  @Test
  public void test() {
    PowerMockito.mockStatic(Runtime.class);

    when(Runtime.getRuntime()).thenReturn(mockRuntime);
    when(mockRuntime.exec()).thenReturn("whatever you want");

    // do the rest of your test
  }
}

我认为你是正确的!!我忘记使用mockStatic,而只是使用了mock。我现在会进行测试!谢谢 - Panos
1
好的。尽管它似乎在嘲笑,但最终它似乎忽略了嘲笑并实际上寻找要执行的脚本... 有什么想法吗? - Panos

1
一个工作示例:
src/main/java/sandbox/xx中,XX.java。
package sandbox.xx;

import java.io.File;
import java.io.IOException;

class XX {
    Process run(final String command) throws IOException {

        return this.run(command, null, null);
    }

    Process run(final String command, final String[] envp) throws IOException {

        return this.run(command, envp, null);
    }

    Process run(final String command, final String[] envp, final File dir) throws IOException {

        return Runtime.getRuntime().exec(command, envp, dir);
    }

    Process run(final String[] cmdarray) throws IOException {

        return this.run(cmdarray, null, null);
    }

    Process run(final String[] cmdarray, final String[] envp) throws IOException {

        return this.run(cmdarray, envp, null);
    }

    Process run(final String[] cmdarray, final String[] envp, final File dir) throws IOException {

        return Runtime.getRuntime().exec(cmdarray, envp, dir);
    }
}

src/test/java/sandbox/xx 中,XXTest.java。
package sandbox.xx;

import java.io.IOException;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatchers;
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(XX.class) // watch it: not @PrepareForTest(Runtime.class)!
public class XXTest {

    private static final String TRIGGER_ARG = "some arg";
    private static final String EXPECTED_PREFIX = "gotcha!";
    private static final String COLON = ": ";
    private static final String EXPECTED_RESULT = EXPECTED_PREFIX + COLON + TRIGGER_ARG;

    @Test
    public void test() throws IOException {

        final Runtime mockRuntime = PowerMockito.mock(Runtime.class);
        PowerMockito.mockStatic(Runtime.class);

        Mockito.when(Runtime.getRuntime()).thenReturn(mockRuntime);
        Mockito.when(mockRuntime.exec(ArgumentMatchers.eq(TRIGGER_ARG), ArgumentMatchers.any(), ArgumentMatchers.any())).thenAnswer(invocation -> {
            final Process mockProcess = PowerMockito.mock(Process.class);
            Mockito.when(mockProcess.toString()).thenReturn(EXPECTED_PREFIX + COLON + invocation.getArguments()[0]);
            return mockProcess;
        });

        final XX xx = new XX();
        Assert.assertEquals(EXPECTED_RESULT, xx.run(TRIGGER_ARG).toString());
        Assert.assertNull(xx.run("some other arg"));
    }
}

希望这能帮到您。

0

模拟运行时总是很棘手,特别是对于复杂的项目。我以前做过这个,但几乎不可能坚持使用一个模拟框架。因此,我在项目类中使用了Easymock,而在运行时使用了Powermock。但这真的很复杂,对于下一个开发人员来说也不容易阅读。 因此,我的建议是在您的项目中保留一个类,该类仅调用一个运行时方法(对于您来说,它是exec,同样,如果您想调用halt()方法,请将其保留在单独的类中)。然后使用Mockito为该类使用运行时方法,并验证相同的模拟。 祝你好运!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接