java - ¿Hay alguna manera en JMockit de llamar al método original desde un método burlado?
mocking (3)
En mi clase de simulacro, me estoy burlando del método foo (). Para algunos casos de prueba, quiero que la implementación simulada de foo () devuelva un valor especial. Para otros casos de prueba, quiero usar la implementación real de foo (). Tengo un booleano definido en mi clase simulada para poder determinar en el método simulado si deseo devolver el valor especial o usar el método "real". El problema es que parece que no puedo entender cómo llamar al método real desde el método burlado.
Descubrí que puedes definir un miembro especial dentro del objeto simulado llamado "it" (con el tipo de objeto que se está burlando). Esto le permite hacer referencia a la clase real desde la implementación simulada. Entonces, mi plan era, si necesitaba invocar la implementación "real" de foo (), el método simulado lo llamaría .foo (). Sin embargo, esto no funciona, porque llamar a it.foo () simplemente llama a la versión simulada de nuevo, no a la versión real, así que termino con recursión infinita.
¿Hay alguna forma de hacer que esto funcione?
EDITAR: podría ser más claro con un ejemplo de código, así es como se ve mi implementación de método simulado actual:
private RealClass it;
...
public SomeClass foo() {
if(fakeIt) {
return new SomeClass("fakevalue");
} else {
// doesn''t work, just keeps calling the mock foo
// in infinite recursion
return it.foo();
}
}
EDIT 2: Además, para la mayoría de mis casos de prueba NO quiero la implementación simulada. Así que mi intento inicial fue solo llamar a Mockit.redefineMethods () dentro de esos casos de prueba donde necesitaba el objeto simulado. Pero esto no funcionó, parece que solo puedes hacer esto en configuración / desmontaje ... mi implementación simulada nunca se llamó cuando intenté eso.
NOTAS SOBRE LA SOLUCIÓN:
Al principio no pensé que la respuesta ofrecida funcionara, pero después de jugar con ella un poco más, parece que el problema es que estaba mezclando los métodos "core" de JMockit con los métodos "anotación". Aparentemente al usar la anotación necesita usar Mockit.setupMocks, no Mockit.redefineMethods (). Esto es lo que finalmente funcionó:
@Before
public void setUp() throws Exception
{
Mockit.setUpMocks(MyMockClass.class);
}
Entonces, para la clase falsa:
@MockClass(realClass = RealClass.class)
public static class MyMockClass {
private static boolean fakeIt = false;
private RealClass it;
@Mock(reentrant = true)
public SomeClass foo() {
if(fakeIt) {
return new SomeClass("fakevalue");
} else {
return it.foo();
}
}
}
En lugar de arrojar un objeto simulado, también podría subclasificar el objeto que desea probar y anular los métodos que deberían devolver valores especiales.
Por ejemplo:
RealClass toTest = new RealClass(){
public String foo(){
return "special value";
}
}
//use toTest in test
Al mantener esta definición dentro de su prueba, también queda claro para otros qué métodos se están "burlando".
Creo que puedes hacer esto con la anotación @Mock
. De los documentos, @Mock(reentrant=true)
en tu clase simulada debería hacerlo.
Ver http://jmockit.googlecode.com/svn/trunk/www/javadoc/mockit/Mock.html
Para ver un ejemplo, mira aquí http://jmockit.googlecode.com/svn/trunk/www/tutorial/StateBasedTesting.html#reentrant
No he probado esto sin embargo ..
En versiones más recientes de JMockit, se puede invocar Invocation.proceed()
desde una implementación de MockUp
. Ver Falsificación: proceder a la implementación real .
public class MyMockClass extends MockUp<RealClass> {
private static boolean fakeIt = false;
@Mock
public SomeClass foo(Invocation inv) {
if (fakeIt) {
return new SomeClass("fakevalue");
} else {
return inv.proceed();
}
}
}