2010-09-07 12 views
43

Mi código:muelle 3 autowiring y JUnit prueba

@Component 
public class A { 
    @Autowired 
    private B b; 

    public void method() {} 
} 

public interface X {...} 

@Component 
public class B implements X { 
    ... 
} 

quiero probar en aislamiento clase A. ¿Tengo que simulacro de clase B? Si es así, ¿cómo? Porque está auto-conectado y no hay un setter donde pueda enviar el objeto burlado.

Respuesta

81

quiero probar en aislamiento clase A.

Usted debe absolutamente simulacro B, en lugar de crear una instancia e inyectar una instancia de B. El punto es poner a prueba un si o no las obras B, por lo no debe permitir que un B potencialmente roto interfiera con la prueba de A.

Dicho esto, recomiendo encarecidamente Mockito. Como van los marcos burlones, 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 
} 
+32

+1 por burlarse de getMeaningOfLife() a 42 :-). – Dave

+11

Con la nueva versión de Mockito, utilizaría la anotación '@ InjectMocks' en la declaración de' A' y me desharé del reflejo 'setField (..)' – Snekse

+0

Pero a es un bean, es decir, un proxy (creado con AOP). Esto no tendrá éxito. He intentado algo similar y el error fue que el campo b no se pudo encontrar en A (porque es un proxy). –

15

Puede inyectar el campo a través de la reflexión con Spring ReflectionTestUtils.setField (o la extensión junit PrivateAccessor) o puede crear un contexto de aplicación simulada y cargar eso. Aunque para una prueba simple de unidad (no integración), prefiero usar la reflexión para simplificar.

0

This forum discussion tiene sentido para mí. Puede declarar su miembro privado b como un tipo de InterfaceB que es implementado por la clase B (es decir, orientado al servicio) y luego declarar que una clase MockB también implementaría la misma interfaz. En el contexto de la aplicación del entorno de prueba, declaras la clase MockB y el contexto de tu aplicación de producción declaras la clase B normal y, en cualquier caso, el código para la clase A no necesita cambiarse ya que se autoconectará.

+1

Con @Autowire no declara sus granos en el contexto de aplicación, sólo están aquí en la ruta de clase. Entonces, esta solución no funciona. – Damien

+0

Esta solución funciona si conecta el bean por tipo (en 2.5) o declara un calificador (3.0). En Spring 2.5 puede conectarse automáticamente a un bean declarado en su configuración de contexto de aplicación XML, como se puede leer en la documentación http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory- autowire. En Spring 3.0 todavía te permiten hacer esto con la anotación @Qualifier (documentada en http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans- autowired-anotación). – Aaron

18

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); 
    } 
} 
+6

Si no utiliza 'MockitoJUnitRunner', es importante recordar en' FooServiceTest': \t '@Before \t initMocks public void() { \t \t MockitoAnnotations.initMocks (this); \t} ' – TalkLittle