Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Runtime.getRuntime().exec jUnit test

Tags:

I have a class that in some of its methods is using

Runtime.getRuntime().exec ...

For example:

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

Unfortunately I "cannot refactor" the class due to some requirements. I want to create jUnit tests on this class and I'm finding it hard to mock the Runtime class.

Let's say I want to test the "doSomething" method in the cases where Runtime process returns the X result or the Y result. Is there any way to mock it?

like image 555
Panos Avatar asked Jun 20 '16 17:06

Panos


2 Answers

You can do that using PowerMockito and mockStatic method.

The idea is to mock the static Runtime.getRuntime() method to return a mocked runtime object, and on that you can control the outcome of 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
  }
}
like image 144
Nir Levy Avatar answered Sep 28 '22 04:09

Nir Levy


A working example :

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

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

Hope this helps

like image 34
Sxilderik Avatar answered Sep 28 '22 03:09

Sxilderik