que ejemplos contenedores componentes componente component clase biblioteca java unit-testing junit mockito

java - ejemplos - Mockito: ¿cómo verificar que se haya llamado al método en un objeto creado dentro de un método?



contenedores en java (7)

Creo que Mockito @InjectMocks es el camino a seguir.

Dependiendo de tu intención puedes usar:

  1. Inyección de constructor
  2. Iniciador de propiedades de inyección
  3. Inyección de campo

Más información en docs

A continuación se muestra un ejemplo con inyección de campo:

Clases:

public class Foo { private Bar bar = new Bar(); public void foo() { bar.someMethod(); } } public class Bar { public void someMethod() { //something } }

Prueba:

@RunWith(MockitoJUnitRunner.class) public class FooTest { @Mock Bar bar; @InjectMocks Foo foo; @Test public void FooTest() { doNothing().when( bar ).someMethod(); foo.foo(); verify(bar, times(1)).someMethod(); } }

Soy nuevo en Mockito.

Dada la siguiente clase, ¿cómo puedo usar Mockito para verificar que se invocó someMethod exactamente una vez después de invocar foo ?

public class Foo { public void foo(){ Bar bar = new Bar(); bar.someMethod(); } }

Me gustaría hacer la siguiente llamada de verificación,

verify(bar, times(1)).someMethod();

donde bar es una instancia burlada de Bar .


La respuesta clásica es: "Tú no". Pruebas la API pública de Foo , no sus componentes internos.

¿Hay algún comportamiento del objeto Foo (o, menos bueno, algún otro objeto en el entorno) que esté afectado por foo() ? Si es así, prueba eso. Y si no, ¿qué hace el método?



Sí, si realmente quieres o necesitas hacerlo, puedes usar PowerMock. Esto debe ser considerado como un último recurso. Con PowerMock puede hacer que devuelva un simulacro de la llamada al constructor. A continuación, haga la verificación en el simulacro. Dicho esto, csturtz es la respuesta "correcta".

Aquí está el enlace a la construcción simulada de nuevos objetos.


Si no quieres usar DI o Fábricas. Puedes refactorizar tu clase de una manera un poco complicada:

public class Foo { private Bar bar; public void foo(Bar bar){ this.bar = (bar != null) ? bar : new Bar(); bar.someMethod(); this.bar = null; // for simulating local scope } }

Y tu clase de prueba:

@RunWith(MockitoJUnitRunner.class) public class FooTest { @Mock Bar barMock; Foo foo; @Test public void testFoo() { foo = new Foo(); foo.foo(barMock); verify(barMock, times(1)).someMethod(); } }

Entonces la clase que está llamando a tu método foo lo hará así:

public class thirdClass { public void someOtherMethod() { Foo myFoo = new Foo(); myFoo.foo(null); } }

Como puede ver al llamar al método de esta manera, no necesita importar la clase Bar en ninguna otra clase que esté llamando a su método foo, que tal vez sea algo que desee.

Por supuesto, el inconveniente es que está permitiendo que la persona que llama establezca el objeto Barra.

Espero eso ayude.


Solución para su código de ejemplo usando PowerMockito.whenNew

  • mockito-todo 1.10.8
  • powermock-core 1.6.1
  • powermock-module-junit4 1.6.1
  • powermock-api-mockito 1.6.1
  • Junit 4.12

FooTest.java

package foo; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Mockito; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; //Both @PrepareForTest and @RunWith are needed for `whenNew` to work @RunWith(PowerMockRunner.class) @PrepareForTest({ Foo.class }) public class FooTest { // Class Under Test Foo cut; @Mock Bar barMock; @Before public void setUp() throws Exception { cut = new Foo(); } @After public void tearDown() { cut = null; } @Test public void testFoo() throws Exception { // Setup PowerMockito.whenNew(Bar.class).withNoArguments() .thenReturn(this.barMock); // Test cut.foo(); // Validations Mockito.verify(this.barMock, Mockito.times(1)).someMethod(); } }

Salida de JUnit


Inyección de dependencia

Si inyecta la instancia de la barra, o una fábrica que se utiliza para crear la instancia de la barra (o una de las otras 483 formas de hacerlo), tendrá el acceso necesario para realizar la prueba.

Ejemplo de fábrica:

Dada una clase de Foo escrita así:

public class Foo { private BarFactory barFactory; public Foo(BarFactory factory) { this.barFactory = factory; } public void foo() { Bar bar = this.barFactory.createBar(); bar.someMethod(); } }

en su método de prueba puede inyectar un BarFactory como este:

@Test public void testDoFoo() { Bar bar = mock(Bar.class); BarFactory myFactory = new BarFactory() { public Bar createBar() { return bar;} }; Foo foo = new Foo(myFactory); foo.foo(); verify(bar, times(1)).someMethod(); }

Bonificación: este es un ejemplo de cómo TDD puede impulsar el diseño de su código.