代码之家  ›  专栏  ›  技术社区  ›  Rich

模拟运行时.getRuntime()?

  •  14
  • Rich  · 技术社区  · 16 年前

    有人能就如何最好地使用easymock来期望电话 Runtime.getRuntime().exec(xxx) ?

    我可以将调用转移到另一个实现接口的类中的方法中,但不希望在理想的环境中进行。

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

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

    4 回复  |  直到 15 年前
        1
  •  13
  •   Bozho    16 年前

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

    作为旁注,我建议看 this lecture on OO Design for testability .

    更新: 我没有看到私人建造师。您可以尝试使用 java bytecode instrumentation 为了添加另一个构造函数或使构造函数成为公共的,但这也可能是不可能的(如果对该类有一些限制的话)。

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

        2
  •  6
  •   Community Mohan Dere    8 年前

    Bozho 上面是我的 正确的解决方案 . 但这并不是唯一的解决办法。你可以使用 PowerMock JMockIt .

    使用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();
        }
    }
    
        3
  •  1
  •   Nate    16 年前

    也许不是嘲笑 Runtime.getRuntime().exec() 你可以“模仿”脚本/程序等,它应该在调用。

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

        4
  •  0
  •   Rogério    15 年前

    以下是使用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");
        }
    }