2012-02-09 21 views
14

Estoy intentando escribir clase de prueba para el siguiente métodoprimavera inyección en Mockito

public class CustomServiceImpl implements CustomService { 
    @Value("#{myProp['custom.url']}") 
    private String url; 
    @Autowire 
    private DataService dataService; 

estoy usando el valor url inyectado en uno de los métodos de la clase. Para probar esto que he escrito una clase JUnit

@RunWith(MockitoJUnitRunner.class) 
@ContextConfiguration(locations = { "classpath:applicationContext-test.xml" }) 
public CustomServiceTest{ 
    private CustomService customService; 
    @Mock 
    private DataService dataService; 
    @Before 
    public void setup() { 
     customService = new CustomServiceImpl(); 
     Setter.set(customService, "dataService", dataService); 
    }  
    ... 
} 

public class Setter { 
    public static void set(Object obj, String fieldName, Object value) throws Exception { 
     Field field = obj.getClass().getDeclaredField(fieldName); 
     field.setAccessible(true); 
     field.set(obj, value); 
    } 
} 

En applicationContext-test.xml Estoy cargando el archivo de propiedades utilizando

<util:properties id="myProp" location="myProp.properties"/> 

Pero el valor url no está consiguiendo cargado en la CustomService en correr la prueba. Me preguntaba si hay alguna forma de hacerlo.

Gracias

+4

Si se está burlando de 'CustomService', ¿cómo se usa' CustomServiceImpl'? Eso no tiene sentido. – skaffman

+0

Estoy usando CustomeServiceImpl. Actualizado el código ¿Cómo puedo simular el valor de url que debe leerse en el archivo de propiedades? – rohit

+1

Tal como está ahora, no está usando Spring para establecer el valor de servicio personalizado, estableciendo el valor manualmente en el método setup() con este código: 'customService = new CustomServiceImpl();' – DwB

Respuesta

3

Puede autoaumentar en un mutador (setter), en lugar de solo anotar el campo privado. Entonces también puedes usar ese setter de tu clase de prueba. No es necesario hacerlo público, el paquete privado lo hará ya que Spring aún puede acceder a él, pero de lo contrario solo su prueba puede ingresar ahí (u otro código en el mismo paquete).

@Value("#{myProp['custom.url']}") 
String setUrl(final String url) { 
    this.url = url; 
} 

No soy un fan de Autowiring diferente (en comparación con mi base de código) sólo para las pruebas, pero la alternativa de cambiar la clase bajo prueba, de la prueba, es simplemente profano.

+0

¿sabes si esto también funciona con la anotación '@ Resource'? – OscarRyz

1

Usted no debe burlarse de lo que usted está tratando de probar. Eso no tiene sentido ya que no tocará el código que está intentando probar. En su lugar, obtenga la instancia de CustomerServiceImpl del contexto.

+0

No cometas el pecado capital de las Pruebas unitarias. –

12

Acepto el comentario de @skaffman.

Además de su prueba utiliza el MockitoJUnitRunner, por lo tanto, no buscará ningún material de Spring, este único propósito es inicializar Mockito mocks. El ContextConfiguration no es suficiente para conectar cosas con la primavera. Técnicamente con JUnit puedes usar el siguiente corredor si quieres cosas relacionadas con la primavera: SpringJUnit4ClassRunner.

También como está escribiendo un Unidad de prueba es posible que desee reconsiderar el uso de la primavera. El uso de cableado de primavera en una prueba de unidad es incorrecto. Sin embargo, si en su lugar está escribiendo Prueba de integración, ¿por qué está utilizando Mockito allí, no tiene sentido (como lo dijo skaffman)!

EDIT: Ahora en su código a a directamente establecer el CustomerServiceImpl en el bloque anterior, eso tampoco tiene sentido. ¡Spring no está involucrado en absoluto!

@Before 
public void setup() { 
    customService = new CustomServiceImpl(); 
    Setter.set(customService, "dataService", dataService); 
} 

EDIT 2: Si desea escribir una prueba Unidad deCustomerServiceImpl, entonces es mejor evitar las cosas primavera e inyectar directamente el valor de la propiedad. También podría usar Mockito para inyectar el DataService falso en la instancia probada.

@RunWith(MockitoJUnitRunner.class) 
public CustomServiceImplTest{ 
    @InjectMocks private CustomServiceImpl customService; 
    @Mock private DataService dataService; 

    @Before void inject_url() { customerServiceImpl.url = "http://..."; } 

    @Test public void customerService_should_delegate_to_dataService() { ... } 
} 

Como habrá notado que estoy usando un acceso directo al campo url, el campo se puede empaquetar visible. Esta es una solución de prueba para inyectar realmente el valor de URL ya que Mockito solo inyecta mocks.

+0

Al "reconsiderar el uso de la primavera", quiere reconsiderar el uso de los archivos de configuración de Spring para realizar la inyección de dependencia para _este test_, ¿verdad? No está sugiriendo que abandone el uso de Spring en su aplicación. – jhericks

+4

@jhericks No, quise eliminar el código relacionado con Spring en Unit Test. Por lo general, tengo una línea dura en esto: desaconsejo el uso de código de pegamento como Sprin en cualquier ** Prueba unitaria **. El objetivo de ** Unit Test ** es probar de forma aislada el código de producción (aquí 'CustomerServiceImpl'). Esta parece ser la intención del autor del problema. Si se requiere un resorte por alguna razón, entonces comienza a ser un ** Test de Integración ** que no tiene las mismas implicaciones en la prueba. – Brice

+0

EDIT 2 solucionó mi problema, ¡gracias! –

31
import org.springframework.test.util.ReflectionTestUtils; 

@RunWith(MockitoJUnitRunner.class) 
public CustomServiceTest{ 

@InjectMock 
private CustomServiceImpl customService; 

@Mock 
private DataService dataService; 

@Before 
public void setup() { 
    ReflectionTestUtils.setField(customService, "url", "http://someurl"); 
}  
... 
} 
+0

¿Podría explicar también su solución con algunas palabras? – Magnilex

+0

La pregunta de Rohit podría tener otros problemas, pero mientras buscaba una solución a mi problema, esta solución era exactamente lo que quería, gracias Robert – mikeapr4

+0

¡Simple y funcional, me encanta! –

1

Tenía una lista de cadenas de lectura del archivo de propiedades. El método setField de la clase ReflectionTestUtils utilizado en el bloque @Before me ayudó a establecer estos valores antes de la ejecución de mi prueba. Funcionó perfectamente incluso para mi capa dao, que depende de la clase Common DaoSupport.

@Before 
public void setList() { 
    List<String> mockedList = new ArrayList<>(); 
    mockedSimList.add("CMS"); 
    mockedSimList.add("SDP"); 
    ReflectionTestUtils.setField(mockedController, "ActualListInController", 
      mockedList); 
} 
Cuestiones relacionadas