mock injectmocks java unit-testing mockito inject

java - injectmocks - mockito spy



Mockito @InjectMocks no funciona para campos del mismo tipo (2)

Esto se documenta en mockito como solución alternativa, si existen varios simulacros del mismo tipo. No resuelve la implementación en función del nombre proporcionado (es decir, @Mock(name = "b2") ). El algoritmo que utiliza para resolver la implementación es por el nombre de campo de la dependencia inyectada. Por lo tanto, su código anterior se resolverá correctamente ( b2 => @Mock private B b2 y b3 => @Mock private B b3 ).

La otra solución es utilizar la inyección de constructor, que es la forma recomendada de inyectar dependencias.

Me sorprendió mucho descubrir que el siguiente ejemplo de código simple no funciona para todas las versiones de Mockito> 1.8.5

@RunWith(MockitoJUnitRunner.class) public class MockitoTest { @Mock(name = "b2") private B b2; @InjectMocks private A a; @Test public void testInjection() throws Exception { assertNotNull(a.b2); //fails assertNull(a.b1); //also fails, because unexpectedly b2 mock gets injected here } static class A{ private B b1; private B b2; } interface B{} }

En javadocs ( http://docs.mockito.googlecode.com/hg/latest/org/mockito/InjectMocks.html ) hay una cita:

Nota 1: Si tiene campos con el mismo tipo (o el mismo borrado), es mejor nombrar todos los campos anotados de @Mock con los campos correspondientes, de lo contrario, Mockito podría confundirse y la inyección no ocurrirá.

¿Significa que si tengo varios campos del mismo tipo no puedo simular SOLO UNO de ellos, sino que debería definir @Mock para TODOS los campos del mismo tipo? ¿Se conoce la limitación y hay alguna razón por la cual no se ha corregido todavía? Debería ser sencillo hacer coincidir @Mock por los nombres de los campos, ¿no es así?


Parece que Mockito utiliza un algoritmo descrito en su JavaDoc.

Si entiendo correctamente, primero se ordenará por tipo (en este caso solo 1 B) y luego se ordenará por nombre (sin cambios aquí). Finalmente, se inyectará utilizando la implementación de la interfaz de OngoingInjector , que parece buscar el primer campo e inyectarlo.

Como solo tienes 1 B definido y hay 2 campos de B en el simulacro, verá la coincidencia de la primera instancia con el campo y se detendrá. Esto se debe a que mocks.size() == 1 en NameBasedCandidateFilter . Por lo tanto, dejará de filtrar y lo inyectará directamente. Si crea múltiples simulacros del mismo tipo, se ordenarán en Nombre y se inyectarán en consecuencia.

Pude hacerlo funcionar cuando creé varias simulaciones (pero menos que la cantidad de campos) de un tipo específico.

@RunWith(MockitoJUnitRunner.class) public class MockitoTest { @Mock(name = "b2") private B b2; @Mock(name = "b3") private B b3; @InjectMocks private A a; @Test public void testInjection() { System.out.println(this.a); } static class A { private B b1; private B b2; private B b3; } interface B { } }

Esto inyectará correctamente b2 en a.b2 y b3 en a.b3 en lugar de a.b1 y a.b2 (los primeros 2 campos que se definen en A).

Siempre se puede dejar un problema de GitHub en su repositorio con una mejora o un cambio en el algoritmo de filtrado de inyección para poder verlo.