2011-09-29 20 views
5

A continuación se muestra una configuración simplificada de mi aplicación. Tiene una clase Foobar que recurre a un método de fachada para obtener datos. La fachada llama a un servicio web para obtener los datos y luego manipula los datos un poco y luego los devuelve a Foobar.Prueba de una llamada al método asíncrono

Ahora, dado que el servicio web puede tardar un buen tiempo en ejecutarse, la llamada al método a la fachada debe ser asincrónica. Por lo tanto, el método de la fachada no tiene un valor de retorno, sino que el método utiliza un objeto de devolución de llamada. Mire el ejemplo y continúe leyendo a continuación.

public class Foobar { 
    private List<DTO> dtos; 

    @Autowired 
    private Facade facade; 

    public void refresh() { 
     facade.refreshFoobar(new CallBack() { 
      public void dataFetched(List<DTO> dtos) { 
       setDtos(dtos); 
      } 

     }); 
    }  

    public void setDtos(List<DTO> dtos) { 
     this.dtos = dtos; 
    } 
} 


public class Facade { 

    ... 

    public void refreshFoorbar(CallBack cb) { 
     // Fetch data from a web service 
     List<DTO> dtos = webService.getData(); 
     // Manipulate DTOs 
     .... 
     // call on the callback method 
     cb.dataFecthed(dtos); 
    } 

} 

Tengo dos formas de hacer de la fachada método asincrónico, ya sea mediante la creación de un hilo de forma manual o mediante el uso de muelles @Async anotación.

public class Facade { 

    public void refreshFoorbar(CallBack cb) { 
     new Thread() { 

      @Override 
      public void run() { 
       .... 
      } 

     }.start(); 

    } 
} 

// ... OR ... 

public class Facade { 

    @Async 
    public void refreshFoorbar(CallBack cb) { 
     ....  
    } 
} 

Mi problema es que ahora necesito escribir una prueba de integración para esta cadena de llamadas a métodos. Creo que necesito forzar que la llamada de fachada asíncrona sea sincrónica cuando se ejecuta la prueba de integración; de lo contrario, no sabré con certeza cuándo puedo hacer las afirmaciones correspondientes. La única idea para hacer que el método llame sincrónico es usar hilos manejados manualmente Y hacer que el subproceso sea condicional (por lo tanto, para fines de prueba, tengo una cláusula if que determina si el método de fachada debe ejecutarse en un hilo separado o no).

Sin embargo, tengo la sensación de que podría haber una mejor solución a mi problema, ya sea una mejor manera de forzarme el método sincrónico, por ejemplo, con resorte, o probando el multihilo de alguna manera.

Aquí es donde necesito sus sugerencias, ¿cómo resolvería mi problema? Tenga en cuenta que estoy usando junit para las pruebas de unidad y de integración.

+0

No sé si es la forma correcta. Por lo general, la prueba de las condiciones asincrónicas es simplemente iniciar la tarea asíncrona, esperar un tiempo y probar si la tarea se ha completado. – SJuan76

Respuesta

6

Cuando JUnit prueba cosas como esta, utilizo una prueba de devolución de llamada con un CountDownLatch que se cuenta por la devolución de llamada y await() ed por el método de prueba.

private static class TestingCallback implements Callback { 
    private final CountDownLatch latch; 
    public TestingCallback(CountDownLatch latch) { 
     this.latch = latch; 
    } 
    @Override public void onEvent() { 
     this.latch.countDown(); 
    } 
} 

@Test 
public void testCallback() { 
    final CountDownLatch latch = new CountDownLatch(1); 

    classUnderTest.execute(new TestCallback(latch)); 

    assertTrue(latch.await(30, TimeUnit.SECONDS)); 
} 

Si la devolución de llamada se invoca (de forma asíncrona) por el código bajo prueba, el pestillo vuelve true y pasa la prueba. Si la devolución de llamada no se invoca, la prueba expira después de treinta segundos y la aserción falla.

12

Una solución sencilla sería la de devolver un objeto futuro de este tipo,

@Async 
public Future<String> refreshFoorbar(CallBack cb) { 
    yourHeavyLifting(); //asynchronous call 
    return new AsyncResult<String>("yourJobNameMaybe"); 
} 

Y en su prueba, tomar la referencia futura y llame al método get().

future.get(); // if its not already complete, waits for it to complete 
assertTrue(yourTestCondition) 

blog post muestra una muestra.

+0

vea esto si ayuda http://www-01.ibm.com/support/knowledgecenter/SSCKBL_8.5.5/com.ibm.websphere.nd.multiplatform.doc/ae/tejb_clientcode.html –

Cuestiones relacionadas