how examples all mockito

examples - Mockito Cómo burlarse solo de la llamada de un método de la superclase



mockito verify (7)

Considere refactorizar el código del método ChildService.save () a un método diferente y pruebe ese nuevo método en lugar de probar ChildService.save (), de esta forma evitará llamadas innecesarias al supermétodo.

Ejemplo:

class BaseService { public void save() {...} } public Childservice extends BaseService { public void save(){ newMethod(); super.save(); } public void newMethod(){ //some codes } }

Estoy usando Mockito en algunas pruebas.

Tengo las siguientes clases:

class BaseService { public void save() {...} } public Childservice extends BaseService { public void save(){ //some code super.save(); } }

Quiero super.save solo la segunda llamada ( super.save ) de ChildService . La primera llamada debe llamar al método real. ¿Hay una manera de hacer eso?


Incluso si estoy totalmente de acuerdo con la respuesta iwein (

favorecer la composición sobre la herencia

), admito que algunas veces la herencia parece simplemente natural, y no siento que se rompa o refactorice solo por el bien de una prueba unitaria.

Por lo tanto, mi sugerencia:

/** * BaseService is now an asbtract class encapsulating * some common logic callable by child implementations */ abstract class BaseService { protected void commonSave() { // Put your common work here } abstract void save(); } public ChildService extends BaseService { public void save() { // Put your child specific work here // ... this.commonSave(); } }

Y luego, en la prueba unitaria:

ChildService childSrv = Mockito.mock(ChildService.class, Mockito.CALLS_REAL_METHODS); Mockito.doAnswer(new Answer<Void>() { @Override public Boolean answer(InvocationOnMock invocation) throws Throwable { // Put your mocked behavior of BaseService.commonSave() here return null; } }).when(childSrv).commonSave(); childSrv.save(); Mockito.verify(childSrv, Mockito.times(1)).commonSave(); // Put any other assertions to check child specific work is done


La razón es que su clase base no es pública, luego Mockito no puede interceptarla debido a la visibilidad, si cambia la clase base como pública o @Override en la subclase (como pública), entonces Mockito puede simularlo correctamente.

public class BaseService{ public boolean foo(){ return true; } } public ChildService extends BaseService{ } @Test @Mock ChildService childService; public void testSave() { Mockito.when(childService.foo()).thenReturn(false); // When assertFalse(childService.foo()); }


No, Mockito no es compatible con esto.

Puede que esta no sea la respuesta que está buscando, pero lo que está viendo es un síntoma de no aplicar el principio de diseño:

Favorecer la composición sobre la herencia

Si extraes una estrategia en lugar de extender una súper clase, el problema desaparece.

Sin embargo, si no puede cambiar el código, pero debe probarlo de todos modos, y de esta manera incómoda, todavía hay esperanza. Con algunas herramientas de AOP (por ejemplo, AspectJ) puede tejer código en el método de superclase y evitar su ejecución por completo (yuck). Esto no funciona si está utilizando proxies, tiene que usar la modificación del código de bytes (ya sea carga de tiempo de tejido o tiempo de compilación). También existen marcos de burla que también respaldan este tipo de truco, como PowerMock y PowerMockito.

Te sugiero que vayas a la refactorización, pero si eso no es una opción, te espera un poco de diversión.


Si realmente no tiene otra opción para refactorizar, puede simular o rescindir todo en la llamada a supermétodo, por ejemplo

class BaseService { public void validate(){ fail(" I must not be called"); } public void save(){ //Save method of super will still be called. validate(); } } class ChildService extends BaseService{ public void load(){} public void save(){ super.save(); load(); } } @Test public void testSave() { ChildService spy = Mockito.spy(new ChildService()); // Prevent/stub logic in super.save() Mockito.doNothing().when((BaseService)spy).validate(); // When spy.save(); // Then verify(spy).load(); }


Tal vez la opción más sencilla si la herencia tiene sentido es crear un nuevo método (paquete privado ??) para llamar al súper (vamos a llamarlo superFindall), espiar la instancia real y luego simular el método superFindAll () de la manera en que quisiste simular el padre de clase uno. No es la solución perfecta en términos de cobertura y visibilidad, pero debería hacer el trabajo y es fácil de aplicar.

public Childservice extends BaseService { public void save(){ //some code superSave(); } void superSave(){ super.save(); } }


cree un método de paquete protegido (asume la clase de prueba en el mismo paquete) en la subclase que llama al método de superclase y luego llame a ese método en su método de subclase anulado. a continuación, puede establecer expectativas en este método en su prueba mediante el uso del patrón de espía. no es bonito, pero sin duda es mejor que tener que lidiar con todas las expectativas del súper método en su prueba