Runtime.getRuntime()。exec jUnit test

时间:2016-06-20 17:02:01

标签: java unit-testing

我有一个类在其某些方法中使用

Runtime.getRuntime().exec ...

例如:

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

不幸的是我"无法重构"该课程由于一些要求。我想在这个类上创建jUnit测试,我发现很难模拟Runtime类。

让我们说我想测试" doSomething"运行时进程返回X结果或Y结果的情况下的方法。有没有办法嘲笑它?

3 个答案:

答案 0 :(得分:3)

您可以使用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
  }
}

答案 1 :(得分:0)

一个工作示例:

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"));
    }
}

希望这会有所帮助

答案 2 :(得分:0)

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