2011-05-25 2 views
8

Sto scrivendo del codice che calcola la data e l'ora rispetto all'ora corrente. Nel tempo di Joda, questo è accessibile tramite un costruttore (Java), poiché è un oggetto immutabile. Devo essere in grado di prendere in giro in modo che new DateTime() restituisca uno specifico istante costante in modo da poter fare test asserzioni sensate, ma lasciare tutti gli altri metodi DateTime da solo.In Grails, c'è un buon modo per prendere in giro l'ora corrente usando il tempo di Joda?

Questo si sta rivelando pericoloso. Grails mockFor(DateTime, true) non mi permette di prendere in giro un costruttore Java, ma non c'è un modo non costruttivo ovvio o leggibile di ottenere il tempo in tempo Joda.

Le uniche opzioni disponibili sembrano coinvolgere tecniche JVM di basso livello come il mocking di classe JMockit o EasyMock 3, che sono un problema di Grails. C'è un modo semplice/diretto per raggiungere questo obiettivo?

risposta

5

abbiamo finito per creare dateService con now() metodo. Nel test di unità deridiamo con

domainInstance.dateService = [ now: { currentTime } ] as DateService 

dove currentTime è un campo unità classe di test. Questo impone la dipendenza di tutti su dateService (la nostra unica dipendenza quasi globale), e per le classi src si deve passarlo a mano.

Test unitari, OTOH, sembrano abbastanza chiari.

+0

Ottima risposta. Speravo in qualche modo di evitare di architettare il sistema in modo diverso solo per rendere possibile questo test, ma ho imparato molto su quanto possa essere doloroso fingere costruttori. –

+0

Grazie. Cerco di evitare la chiamata diretta del costruttore - viola il "codice per l'interfaccia", l'istanza creata non può essere esternalizzata come nei test e talvolta porta a 'Construction Blobs'. Quindi si è ridotto a una forma di iniezione di dipendenza. –

2

si potrebbe semplicemente usare buoni principi OO vecchio stile, ad es.

interface TimeService { 
    DateTime getCurrentTime() 

    // other time-related methods 
    } 

    class JodaTimeService implements TimeService { 
    DateTime getCurrentTime() { 
     new DateTime() 
    } 
    } 

    class MockTimeService implements TimeService { 
    DateTime getCurrentTime() { 
     // return a fixed point in time 
    } 
    } 

Il codice dovrebbe ottenere un riferimento a un'implementazione di TimeService tramite iniezione di dipendenza. Nel resources.groovy utilizzare il MockTimeService solo quando si esegue il test

import grails.util.Environment 

beans = {  
    if (Environment.current == Environment.TEST) { 
     timeService(MockTimeService) 

    } else { 
     timeService(JodaTimeService) 
    } 
} 
+0

Indipendentemente dallo stesso approccio di cui sopra, così tante grazie e una buona soluzione ha funzionato a fondo. E grazie extra per i suggerimenti sull'utilizzo dell'ambiente di test da cambiare. –

18

So che questo è già stato accettato, ma con Joda-time puoi congelarlo e impostarlo come vuoi. Quindi puoi bloccare il tempo, avanzare il tempo, andare indietro nel tempo. A patto che tu stia usando Joda in modo coerente, i tuoi oggetti diventeranno "ora" come qualsiasi ora tu abbia impostato per essere.

// Stop time (and set a particular point in time): 
DateTimeUtils.setCurrentMillisFixed(whenever); 

// Advance time by the offset: 
DateTimeUtils.setCurrentMillisOffset(offsetFromCurrent); 

// Restore time (you could do this in an @After method) 
DateTimeUtils.setCurrentMillisSystem(); 
+0

Oooh pulito, speravo in qualcosa di simile. Ciò renderà il test molto più semplice. Grande consiglio !! –

+0

Ora mi sento stupido, perché siamo su Joda. È un modo migliore Bene, ho imparato qualcosa. –