2011-09-29 21 views
5

Di seguito è riportata una configurazione semplificata della mia applicazione. Ha un Foobar di classe che chiama un metodo di facciata per il recupero dei dati. La facciata quindi richiede un servizio Web per ottenere effettivamente i dati e quindi manipola leggermente i dati per poi restituirli a Foobar.Test di una chiamata al metodo asincrono

Ora, poiché il servizio Web potrebbe richiedere un po 'di tempo per essere eseguito, la chiamata del metodo alla facciata deve essere asincrona. Quindi il metodo della facciata non ha un valore di ritorno, ma, invece, il metodo usa un oggetto di callback. Guarda l'esempio e continua a leggere qui sotto.

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

} 

Ho due modi di rendere metodo asincrono della facciata, sia creando un filo manualmente oppure utilizzando molle @Async annotazione.

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) { 
     ....  
    } 
} 

Il mio problema è che ora ho bisogno di scrivere un test di integrazione per questa catena di chiamate di metodo. Penso che sia necessario forzare la chiamata alla facciata asincrona per essere sincrona quando viene eseguito il test di integrazione, altrimenti non saprò per certo quando posso fare le asserzioni appropriate. L'unica idea per fare in modo che la chiamata al metodo sia sincrona consiste nell'utilizzare i thread gestiti manualmente e nel rendere il threading condizionale (quindi, a scopo di test, ho una clausola if che determina se il metodo della facciata deve essere eseguito in un thread separato o meno).

Tuttavia, ho la sensazione che potrebbe esserci una soluzione migliore al mio problema, sia che si tratti di un metodo migliore per forzare il metodo per me sincrono, ad esempio con spring, o testando il multithreading in qualche modo.

Qui è dove ho bisogno dei tuoi suggerimenti, come risolveresti il ​​mio problema? Nota, sto usando junit per i test di unità e di integrazione.

+0

Non so se è il modo corretto. In genere, il test per condizioni asincrone sta avviando l'attività asincrona, attende un po 'e verifica se l'attività è stata completata. – SJuan76

risposta

6

Quando JUnit esegue test di questo tipo, utilizzo una callback di test con un CountDownLatch che viene contato dal callback e await() dal metodo di test.

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

Se il callback viene richiamato (asincrono) dal codice in esame, i rendimenti latch true e il test viene superato. Se il callback non viene richiamato, il test scade dopo trenta secondi e l'asserzione fallisce.

12

soluzione semplice sarebbe quella di restituire un oggetto come questo futuro,

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

E nel test, prendere il riferimento futuro e chiamare il metodo get().

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

Questo blog post mostra un esempio.

+0

vedere questo se aiuta http://www-01.ibm.com/support/knowledgecenter/SSCKBL_8.5.5/com.ibm.websphere.nd.multiplatform.doc/ae/tejb_clientcode.html –

Problemi correlati