2011-12-28 30 views
6

Estoy escribiendo pruebas de unidad para la capa de servicio en mi aplicación de primavera.
Aquí es mi clase de servicioPruebas unitarias con Mockito

@Service 
    public class StubRequestService implements RequestService {  
     @Autowired 
     private RequestDao requestDao; 

     @Transactional(propagation = Propagation.REQUIRED, readOnly = true) 
     @Override 
     public Request getRequest(Long RequestId) { 
      Request dataRequest = requestDao.find(requestId); 
      return dataRequest; 
     } 
    } 

Aquí es mi clase de prueba

@RunWith(MockitoJUnitRunner.class) 
@ContextConfiguration(locations = { "/META-INF/spring/applicationContext.xml" }) 
public class StubRequestServiceTest { 

    @Mock 
    public RequestDao requestDao; 

    StubRequestService stubRequestService; // How can we Autowire this ? 

    @org.junit.Before 
    public void init() { 
     stubRequestService = new StubRequestService(); // to avoid this 
     stubRequestService.setRequestDao(dataRequestDao); 
     // Is it necessary to explicitly set all autowired elements ? 
     // If I comment/remove above setter then I get nullPointerException 
    } 

    @Test 
    public void testGetRequest() { 
     Request request = new Request(); 
     request.setPatientCnt("3"); 
     when(requestDao.find(anyLong())).thenReturn(request); 
     assertEquals(stubRequestService.getRequest(1234L).getPatientCnt(),3); 
    }  
} 

Sus trabajan bien, pero tengo algunas preguntas

  1. ¿Cómo podemos Autowire clase de servicio en la prueba? Estoy usando constructor en el método init() para crear un objeto de servicio.
  2. ¿Tenemos que configurar todos los elementos Autowire para la clase de servicio? Por ejemplo, StubRequestService tengo auto-conectado RequestDao que necesito configurar explícitamente antes de llamar al método de prueba, de lo contrario da nullPointerException como requestDao es en el método StubRequestService.getRequest.
  3. ¿Cuáles son las buenas prácticas a seguir mientras prueba la unidad Capa de servicio de primavera? (Si estoy haciendo algo mal).
+0

Si cambia su pregunta después se dan las respuestas, las respuestas no hacen mucho sentido. Retiraré tu última edición. –

+0

@JB: Disculpas por la edición de preguntas. Solo quería proporcionar información correcta y exacta. Gracias – xyz

Respuesta

3
  1. Si realmente siente que hará que sus pruebas sean más fáciles de entender, puede inicializar un contexto de primavera y buscar todos los objetos desde allí. Sin embargo, generalmente requerirá crear un archivo XML de configuración de primavera separado específicamente para las pruebas, por lo tanto, no lo recomendaría.

    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("testApplicationContext.xml"); 
    stubRequestService = (RequestService)applicationContext.getBean("myRequestServiceBean"); 
    
  2. (y 3) Básicamente, prefiero probar cada componente de mi aplicación en aislamiento total de entre si y por eso no recomiendo lo que se describe en [1].

Lo que esto significa, es tomar una rebanada lógico separado de su solicitud y la prueba única, mientras que totalmente burlarse de todo lo que intenta acceder.

Digamos que usted tiene tres clases:

//Fetches stuff from some webservice and converts to your app domain POJOs 
class DataAccessLayer { 
    public void setWebservice(Webservice ws) {...}; 

    public MyObject getMyObject() {...}; 
} 

//Formats the domain POJOs and sends them to some kind of outputstream or stuff. 
class ViewLayer { 
    public void setOutputStream(OutputStream os) {...}; 

    public void viewMyObject(MyObject mo) {...}; 
} 

//Main entry point of our MyObject fetch-process-display workflow 
class Controller { 
    public void setDataAccessLayer(DataAccessLayer dal) {...}; 
    public void setViewLayer(ViewLayer vl) {...}; 

    public void showMyObject() { 
     MyObject mo = dal.getMyObject(); 
     ...some processing here maybe... 
     vl.viewMyObject(mo); 
    } 
} 

Ahora, ¿qué pruebas podemos escribir aquí?

  1. prueba si DataAccessLayer convierte adecuadamente el objeto de burlado hasta WS en nuestro objeto de dominio.
  2. Pruebe si ViewLayer formatea correctamente el objeto que se le ha asignado y lo escribe en simulacro secuencia de salida.
  3. prueba si Controller toma un objeto de burlado hastaDataAccessLayer procesos correctamente y lo envía al burlado hastaViewLayer.
+0

¿Hay alguna razón específica para usar un archivo de contexto diferente para crear instancias de beans en la prueba? Y gracias por ejemplo. Realmente ayudó mucho. – xyz

+0

No hay ninguna razón, es solo que generalmente sucede que es incompatible con sus pruebas. Por ejemplo, requiere algunos recursos JNDI, tal vez cargue algunas bases de datos (y las pruebas nunca las usen), tal vez algo de seguridad. Entonces, al final, simplemente comienzas a notar que es más fácil crear un archivo de contexto separado para las pruebas. – bezmax

+0

Sí, hay una razón: no desea probar un servicio con el DAO real. Quieres un simulacro de DAO para probar el servicio. Pero sigue el consejo de Max y el mío: no uses un contexto de Spring para los servicios de prueba unitarios. Es posible que desee un contexto Spring para inyectar un Datasource, SessionFactory y TxManager en las pruebas DAO, pero no en las pruebas de servicio. –

7

Su prueba está bien. Ni siquiera tiene que tener la anotación @ContextConfiguration.

El objetivo de los marcos de inyección de dependencias como Spring es poder probar los servicios de la unidad simplemente instanciando, estableciendo dependencias falsas y luego llamando a sus métodos.

Lo está haciendo correctamente. No necesita tener un contexto Spring para tales pruebas unitarias. Es por eso que se llaman pruebas unitarias: lo prueban de forma aislada de todas sus dependencias reales, incluido Spring.

Nota al margen: suponiendo que esté utilizando JUnit, los argumentos del método assertXxx deben intercambiarse. El valor esperado viene antes del valor real. Se vuelve importante cuando la afirmación falla y usted tiene un mensaje como "esperando 6 pero era 3" en lugar de "esperar 3 pero era 6".

+0

Gracias por su respuesta y sugerencia. ¿Significa que deberíamos crear explícitamente un objeto de servicio y establecer toda la dependencia de autoenlace? Se me aconseja que lo conecte automáticamente en lugar de configurarlo manualmente. – xyz

+1

El autoenvío funciona bien cuando se ejecuta la aplicación. No es necesario, ni siquiera se desea, cuando se realizan pruebas unitarias, ya que cada prueba querrá inyectar sus propias dependencias falsas. –