模拟 Runtime.getRuntime()?

发布于 2024-08-21 14:22:19 字数 343 浏览 8 评论 0原文

任何人都可以就如何最好地使用 EasyMock 来期望调用 Runtime.getRuntime().exec(xxx) 提出任何建议吗?

我可以将调用移动到另一个实现接口的类中的方法中,但在理想的情况下我不愿意这样做。

interface RuntimeWrapper {
    ProcessWrapper execute(String command) throws IOException;
}

interface ProcessWrapper {
    int waitFor() throws InterruptedException;
}

我想知道是否有人有其他建议?

Can anyone make any suggestions about how best to use EasyMock to expect a call to Runtime.getRuntime().exec(xxx)?

I could move the call into a method in another class that implements an interface, but would rather not in an ideal world.

interface RuntimeWrapper {
    ProcessWrapper execute(String command) throws IOException;
}

interface ProcessWrapper {
    int waitFor() throws InterruptedException;
}

I was wondering if anyone had any other suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

请你别敷衍 2024-08-28 14:22:19

您的类不应调用 Runtime.getRuntime()。它应该期望将 Runtime 设置为它的依赖项,并使用它。然后在您的测试中,您可以轻松地提供模拟并将其设置为依赖项。

作为旁注,我建议观看本次有关面向可测试性的 OO 设计的讲座

更新:我没有看到私有构造函数。您可以尝试使用 java 字节码检测 以便添加另一个构造函数或使构造函数公开,但这也可能是不可能的(如果对该类有一些限制)。

因此,您的选择是制作一个包装器(正如您在问题中所建议的那样),并遵循依赖项注入方法。

Your class shouldn't call Runtime.getRuntime(). it should expect a Runtime to be set as its dependency, and work with it. Then in your test you can easily provide a mock and set it as a dependency.

As a sidenote, I'd suggest watching this lecture on OO Design for testability.

Update: I didn't see the private constructor. You can try using java bytecode instrumentation in order to add another constructor or make the constructor public, but that might turn out to be impossible as well (if there are some restrictions on that class).

So your option is to make a wrapper (as you suggested in the question), and follow the dependency-injection approach.

救星 2024-08-28 14:22:19

上面的 Bozho 是我认为的正确解决方案。但这不是唯一的解决方案。您可以使用 PowerMockJMockIt

使用 PowerMock:

package playtest;

public class UsesRuntime {
    public void run() throws Exception {
        Runtime rt = Runtime.getRuntime();
        rt.exec("notepad");
    }
}


package playtest;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.legacy.PowerMockRunner;

import static org.powermock.api.easymock.PowerMock.*;
import static org.easymock.EasyMock.expect;

@RunWith(PowerMockRunner.class)
@PrepareForTest( { UsesRuntime.class })
public class TestUsesRuntime {

    @Test
    public void test() throws Exception {
        mockStatic(Runtime.class);
        Runtime mockedRuntime = createMock(Runtime.class);

        expect(Runtime.getRuntime()).andReturn(mockedRuntime);

        expect(mockedRuntime.exec("notepad")).andReturn(null);

        replay(Runtime.class, mockedRuntime);

        UsesRuntime sut = new UsesRuntime();
        sut.run();
    }
}

Bozho above is IMO the Correct Solution. But it is not the only solution. You could use PowerMock or JMockIt.

Using PowerMock:

package playtest;

public class UsesRuntime {
    public void run() throws Exception {
        Runtime rt = Runtime.getRuntime();
        rt.exec("notepad");
    }
}


package playtest;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.legacy.PowerMockRunner;

import static org.powermock.api.easymock.PowerMock.*;
import static org.easymock.EasyMock.expect;

@RunWith(PowerMockRunner.class)
@PrepareForTest( { UsesRuntime.class })
public class TestUsesRuntime {

    @Test
    public void test() throws Exception {
        mockStatic(Runtime.class);
        Runtime mockedRuntime = createMock(Runtime.class);

        expect(Runtime.getRuntime()).andReturn(mockedRuntime);

        expect(mockedRuntime.exec("notepad")).andReturn(null);

        replay(Runtime.class, mockedRuntime);

        UsesRuntime sut = new UsesRuntime();
        sut.run();
    }
}
千里故人稀 2024-08-28 14:22:19

也许您可以“模拟”脚本/程序/等,而不是模拟Runtime.getRuntime().exec()。应该是在打电话。

不要将真正的命令行字符串传递到 exec() 中,而是编写一个测试脚本并执行它。您可以让脚本返回硬编码值,您可以像模拟类一样进行测试。

Perhaps instead of mocking Runtime.getRuntime().exec() you could "mock" the script/program/etc. it's supposed to be calling.

Instead of passing the real command-line string into exec(), write a test script and execute it instead. You could have the script return hard-coded values you could test against just like a mocked class.

笑叹一世浮沉 2024-08-28 14:22:19

以下是使用 EasyMock 3.0(和 JUnit 4)执行此操作的方法:

import org.junit.*;
import org.easymock.*;
import static org.easymock.EasyMock.*;

public final class EasyMockTest extends EasyMockSupport
{
    @Test
    public void mockRuntimeExec() throws Exception
    {
         Runtime r = createNiceMock(Runtime.class);

         expect(r.exec("command")).andReturn(null);
         replayAll();

         // In tested code:
         r.exec("command");

         verifyAll();
    }
}

上述测试的唯一问题是 Runtime 对象需要传递给被测代码,这会阻止它使用 <代码>Runtime.getRuntime()。
另一方面,使用 JMockit,可以编写以下测试,避免该问题:

import org.junit.*;
import mockit.*;

public final class JMockitTest
{
    @Test
    public void mockRuntimeExec() throws Exception
    {
        final Runtime r = Runtime.getRuntime();

        new NonStrictExpectations(r) {{ r.exec("command"); times = 1; }};

       // In tested code:
       Runtime.getRuntime().exec("command");
    }
}

Here is how you would do it with EasyMock 3.0 (and JUnit 4):

import org.junit.*;
import org.easymock.*;
import static org.easymock.EasyMock.*;

public final class EasyMockTest extends EasyMockSupport
{
    @Test
    public void mockRuntimeExec() throws Exception
    {
         Runtime r = createNiceMock(Runtime.class);

         expect(r.exec("command")).andReturn(null);
         replayAll();

         // In tested code:
         r.exec("command");

         verifyAll();
    }
}

The only problem with the test above is that the Runtime object needs to be passed to code under test, which prevents it from using Runtime.getRuntime().
With JMockit, on the other hand, the following test can be written, avoiding that problem:

import org.junit.*;
import mockit.*;

public final class JMockitTest
{
    @Test
    public void mockRuntimeExec() throws Exception
    {
        final Runtime r = Runtime.getRuntime();

        new NonStrictExpectations(r) {{ r.exec("command"); times = 1; }};

       // In tested code:
       Runtime.getRuntime().exec("command");
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文