primavera 3 autowiring y pruebas junit
Pregunta
Mi código:
@Component
public class A {
@Autowired
private B b;
public void method() {}
}
public interface X {...}
@Component
public class B implements X {
...
}
Quiero poner a prueba en la clase de aislamiento A. ¿Tengo que simulacro de clase B? En caso afirmativo, ¿cómo? Debido a que se autowired y no hay colocador en el que podía enviar el objeto burlado.
Solución
Quiero la prueba en clase de aislamiento A.
Se debe absolutamente simulacro B, en lugar de instanciar e inyectar una instancia de B. El punto es que la prueba A B si las obras o no, por lo que debe no permite un B potencialmente roto interfiere con la prueba de A.
Dicho esto, le recomiendo Mockito . Como marcos burlones van, es extremadamente fácil de usar. Se podría escribir algo como lo siguiente:
@Test
public void testA() {
A a = new A();
B b = Mockito.mock(B.class); // create a mock of B
Mockito.when(b.getMeaningOfLife()).thenReturn(42); // define mocked behavior of b
ReflectionTestUtils.setField(a, "b", b); // inject b into the B attribute of A
a.method();
// call whatever asserts you need here
}
Otros consejos
Aquí hay un ejemplo de cómo llegó a mis pruebas de trabajo con Spring 3.1, JUnit 4.7 y 1.9 Mockito:
FooService.java
public class FooService {
@Autowired private FooDAO fooDAO;
public Foo find(Long id) {
return fooDAO.findById(id);
}
}
FooDAO.java
public class FooDAO {
public Foo findById(Long id) {
/* implementation */
}
}
FooServiceTest.java
@RunWith(MockitoJUnitRunner.class)
public class FooServiceTest {
@Mock private FooDAO mockFooDAO;
@InjectMocks private FooService fooService = new FooService();
@Test public final void findAll() {
Foo foo = new Foo(1L);
when(mockFooDAO.findById(foo.getId()).thenReturn(foo);
Foo found = fooService.findById(foo.getId());
assertEquals(foo, found);
}
}
Se puede inyectar el campo a través de la reflexión utilizando ReflectionTestUtils.setField
de primavera (o la extensión PrivateAccessor
junit) o ??se puede crear un contexto de aplicación simulada y cargar eso. Aunque para una unidad sencilla (no integración) de prueba, estoy a favor de utilizar la reflexión para la simplicidad.
Este foro de debate tiene sentido para mí. Se puede declarar su miembro privado b como un tipo de InterfaceB cual es implementado por la clase B (es decir: orientada al servicio) y luego declarar una clase MockB sería también implementar la misma interfaz. En el contexto de aplicación de entorno de prueba, se declara la clase MockB y su contexto de aplicación de producción se declara la clase B normal y, en cualquier caso, no necesita el código de la clase A que ser cambiado ya que se auto-cableado.