2012-06-01 22 views
6

Tengo una clase donde Runtime.getRuntime() se utiliza para ejecutar un script desde la línea de comandos y obtener el resultado para su posterior procesamiento.¿Cómo ir alrededor de Runtime.getRuntime() mientras se escribe JUnit?

Pero cuando escribo JUnit para esta clase, no puedo encontrar una manera de burlar/evitar este Runtime.getRuntime(). Exec().

No puedo usar EasyMock o PowerMock o cualquier otra aplicación falsa que no sea Mockito.

Por favor, dame una forma de solucionar este problema, porque esto está afectando la cobertura del código.

Respuesta

13

Debe refactorizar. Extraer Runtime.getRuntime().exec() en una clase separada:

public class Shell { 

    public Process exec(String command) { 
    return Runtime.getRuntime().exec(command); 
    } 

} 

Ahora insted de llamar getRuntime() inyectar de forma explícita Shell clase alguna manera a su clase bajo prueba:

public class Foo { 

    private final Shell shell; 

    public Foo(Shell shell) { 
    this.shell = shell; 
    } 

    //... 
    shell.exec(...) 

} 

En la prueba JUnit simplemente inyectar burlado clase Shell pasándolo a constructor :

@Mock 
private Shell shellMock; 

new Foo(shellMock); 

Nota al margen: sí, soy no creando una interfaz Shell con una implementación. ¿Te importa? Mockito no es. Bono: ahora se puede verificar si el proceso correcto se llama:

verify(shellMock).exec("/usr/bin/gimp"); 
+0

HI, ¡Gracias por la respuesta rápida! – unni

+0

Pero, ¿todavía hay alguna otra manera posible? Donde no tengo que cambiar el constructor? Tampoco uses un setter como 'this.shell = shell;' – unni

+0

@ user1147417: No veo ninguna posibilidad, al menos sin PowerMock. '¡Los estáticos son malvados! –

3

Tomasz Nurkiewicz ha dado una respuesta maravillosa. Pero hay una alternativa.

Puede mover Runtime.getRuntime() en su propio método en la clase que está probando; luego pruébalo con un espía Mockito. En el espía de Mockito, puedes anular este método en particular con una versión que crea una falsa Runtime, luego haz lo que quieras con ella.

Sin embargo, el enfoque de Tomasz es más limpio, y lo recomiendo a fondo. Solo quería decir que hay otra forma de hacerlo, sin recurrir a Powermock.

+0

oops David, no vi tu respuesta antes de publicarla nuevamente. Muchas gracias por brindar una solución maravillosa. – unni

0

que utiliza sub-classing y predominante (como se explica en el libro de Michael C. Las plumas 'Trabajar efectivamente con el código heredado')

Supongamos que tenemos el siguiente código:

public class CannotChange{ 
    public CannotChange(){} 
    public void TryingToTest() throws IOException { 
     ... 
     Process proc = Runtime.getRuntime().exec("command"); 
     ... 
    } 
} 

Extracto del tiempo de ejecución código en un método protegido:

public void TryingToTest() throws IOException { 
     ... 
     Process proc = execute("command"); 
     ... 
    } 
    protected Process execute(string command){ 
     return Runtime.getRuntime().exec(command); 
    }  

Luego, en la clase de prueba crear una clase que extiende la clase CannotChange y anula ejecutar

public class CannotChangeTest{ 

    private class CannotChangeForTesting extends CannotChange{ 
     public CannotChangeForTesting(){ super(); } 
     @Override 
     public Process execute(String command){ 
     return null; //or a mocked object 
     } 
    } 

    @Test 
    public void TestMethod(){ 
     CannotChange cannotChange = new ForTestCannotChange(); 
     cannotChange.TryingToTest(); 
    } 
} 
Cuestiones relacionadas