问题
want to write an unittest for a method like
public static void startProgram() {
process = Runtime.getRuntime().exec(command, null, file);
}
I don't want to inject the runtime object for some reasons, so I wanted to stub the getRuntime method that it returns a Runtime mock... I tried it this way:
@RunWith(PowerMockRunner.class)
@PrepareForTest(Runtime.class)
public class ProgramTest {
@Test
public void testStartProgram() {
Runtime mockedRuntime = PowerMockito.mock(Runtime.class);
PowerMockito.mockStatic(Runtime.class);
Mockito.when(Runtime.getRuntime()).thenReturn(mockedRuntime);
... //test
}
}
But this doesn't work. Actually nothing seems to be mocked. In the test the normal Runtime object is used.
Anyone any idea why this doesn't work and/or how it works?
As this mini example seems not to reproduce the problem here is the full test code: method to test (shortened)
public static synchronized long startProgram(String workspace) {
// Here happens someting with Settings which is mocked properly
File file = new File(workspace);
try {
process = Runtime.getRuntime().exec(command, null, file);
} catch (IOException e) {
throw e;
}
return 0L;
}
and the test:
@Test
public void testStartProgram() {
PowerMockito.mockStatic(Settings.class);
Mockito.when(Settings.get("timeout")).thenReturn("42");
Runtime mockedRuntime = Mockito.mock(Runtime.class);
// Runtime mockedRuntime = PowerMockito.mock(Runtime.class); - no difference
Process mockedProcess = Mockito.mock(Process.class);
Mockito.when(mockedRuntime.exec(Mockito.any(String[].class), Mockito.any(String[].class),
Mockito.any(File.class))).thenReturn(mockedProcess);
PowerMockito.mockStatic(Runtime.class);
Mockito.when(Runtime.getRuntime()).thenReturn(mockedRuntime);
startProgram("doesnt matter");
}
Then, in the test, the call to Runtime.getRuntime() doesn't bring the mock and that's why an IOException is thrown because the String is no directory...
回答1:
My bad in the comments, apologies, I had an inner class for the test and that's why I had no trouble. I then realized this and saw your @PrepareForTest(Runtime.class)
which should read @PrepareForTest(MyClass.class)
(replace MyClass with whatever name you have) because Runtime
is a system class. You can read more about this here and find more examples here.
回答2:
You must write a wrapper class for Runtime
, because it's system class.
public class AppShell {
public Process exec(String command) {
return Runtime.getRuntime().exec(command);
}
}
Then in unit test, use @PrepareForTest(AppShell.class)
instead of @PrepareForTest(Runtime.class)
@RunWith(PowerMockRunner.class)
@PrepareForTest(AppShell.class)
public class AppShellTest {
@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
}
}
See PowerMock - Mocking system classes
来源:https://stackoverflow.com/questions/24039184/mock-java-lang-runtime-with-powermockito