2012-03-21 9 views
25

Estoy tratando de escribir una prueba de Unidad para una clase que tiene varios de sus campos marcados como @Autowired. Dado el hecho de que Spring está resolviendo automáticamente las implementaciones concretas para estos campos, me está resultando difícil descifrar cómo conectar mis objetos Mock (creados a través de EasyMock) como las dependencias durante la prueba. Usar @Autowired en la clase significa falta de setters en esa clase. ¿Hay alguna forma de conectar mis objetos simulados sin crear setters adicionales en clase?Unidad probando una clase con notación autocableada usando Junit y EasyMock?

He aquí un ejemplo de lo que estoy tratando de lograr:

public class SomeClassUnderTest implements SomeOtherClass{ 

@Autowired 
private SomeType someType; 

@Autowired 
private SomeOtherType someOtherType; 

@Override 
public SomeReturnType someMethodIWouldLikeToTest(){ 
//Uses someType and someOtherType and returns SomeReturnType 
} 

} 

Así es como estoy visión del mundo en mi clase de prueba antes de chocar con la pared:

public class MyTestClassForSomeClassUnderTest{ 
    private SomeType someType; 
    private SomeOtherType someOtherType; 

    @Before 
    public void testSetUp(){ 
    SomeClassUnderTest someClassToTest = new SomeClassUnderTest(); 
    someType = EasyMock.createMock(SomeType.class); 
    someOtherType = EasyMock.createMock(SomeOtherType.class); 
    //How to set dependencies???? 
    } 

    @Test 
    public void TestSomeMethodIWouldLikeToTest(){ 
    //?????? 
    } 

} 

que será muy bueno para obtener una empujar en la dirección correcta.

Gracias

Respuesta

34

Puede inyectarse reflexivamente dependencias directamente en el campo usando ReflectionTestUtils, por ejemplo

ReflectionTestUtils.setField(testInstance, "fieldName", fieldValue); 

Algunos podrían argumentar que es preferible añadir un método setter paquete visible a la clase de todos modos, utilizado únicamente por las pruebas. Alternativamente, use constructores autocableados, en lugar de campos autoconectados, e inyecte las dependencias de prueba en eso.

+0

Gracias por la punta. –

+1

http://stackoverflow.com/questions/16426323/injecting-into-autowired-variable-during-testing – Dan

+0

EasyMock admite desde la versión 3.2 anotaciones similares a Mockito para inyección simulada. Ver mi respuesta – krm

6

Aunque es posible establecer estos campos por reflexión, al hacerlo evitará que sus herramientas de desarrollo encuentren usos de estos campos, y hará que sea más difícil para usted refactorizar SomeClassToTest en el futuro.

Sería mejor agregar setters públicos para estos campos, y colocar las anotaciones @Autowired en estos. Esto no solo evita la reflexión, sino que también aclara la interfaz externa de la clase y garantiza que la prueba de la unidad solo use esta interfaz. Veo que SomeClassToTest ya implementa la interfaz SomeOtherClass, y supongo que los clientes de SomeClassToTest solo usan esta interfaz, por lo que hay poco peligro en hacer que los setters en SomeClassToTest sean públicos.

Mejor aún, use la inyección de constructor y haga que los campos sean definitivos. Todavía puede usar @Autowired en los argumentos del constructor.

1

No recomiendo la respuesta que se ha aceptado, es decir, utilizando la reflexión por su cuenta (sin un marco de burla).

Desde la versión 3.2 de EasyMock puede usar anotaciones para definir los simulacros e insertarlos en la clase bajo prueba. Una descripción completa de cómo hacerlo se puede encontrar en la documentación oficial de EasyMock: http://easymock.org/user-guide.html#mocking-annotations

He aquí un ejemplo desde el sitio antes mencionado:

import static org.easymock.EasyMock.*; 
import org.easymock.EasyMockRunner; 
import org.easymock.TestSubject; 
import org.easymock.Mock; 
import org.junit.Test; 
import org.junit.runner.RunWith; 

@RunWith(EasyMockRunner.class) 
public class ExampleTest { 

    @TestSubject 
    private ClassUnderTest classUnderTest = new ClassUnderTest(); // 2 

    @Mock 
    private Collaborator mock; // 1 

    @Test 
    public void testRemoveNonExistingDocument() { 
    replay(mock); 
    classUnderTest.removeDocument("Does not exist"); 
    } 
} 
Cuestiones relacionadas