2011-05-25 7 views
8

Piszę kod, który wykonuje obliczenia daty i godziny w stosunku do bieżącego czasu. W czasie Joda dostęp do niego uzyskuje się przez konstruktor (Java), ponieważ jest to obiekt niezmienny. Muszę być w stanie udawać, że new DateTime() zwraca określoną stałą chwilę, więc mogę robić rozsądne twierdzenia testowe, ale pozostawiam wszystkie inne metody DateTime samodzielnie.W Grails, czy istnieje dobry sposób na kpiny z bieżącego czasu za pomocą czasu Joda?

To jest nieprzyjemne. Grails mockFor(DateTime, true) nie pozwoli mi kpić z konstruktora Javy, ale nie ma żadnego oczywistego lub czytelnego, nie-konstruktywnego sposobu na zdobycie czasu w Jodzie.

Dostępne są tylko dostępne techniki JVM niskiego poziomu, takie jak szyderstwo klasy JMockit lub EasyMock 3, które są uciążliwe dla Grails. Czy istnieje prosty/prosty sposób, aby to osiągnąć?

Odpowiedz

5

Skończyło się tworząc dateService z now() metody. W testach jednostkowych my drwić go

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

gdzie currentTime jest polem jednostka klasy testowej. To nakłada na wszystkich zależność od dateService (naszej jedynej prawie globalnej zależności), a dla klas src należy przekazać ją ręcznie.

Testy jednostkowe, OTOH, dzięki nim wyglądają całkiem dobrze.

+0

Świetna odpowiedź. Miałem trochę nadziei, że uniknęłbym projektowania systemu inaczej, aby ten test był możliwy, ale nauczyłem się dużo o tym, jak bolesne może być kpiny z konstruktorów. –

+0

Dzięki. Staram się unikać bezpośredniego wywoływania konstruktora - narusza to "kod interfejsu", utworzona instancja nie może być uzewnętrzniana tak jak w testach, a czasami prowadzi do 'Blobów konstrukcyjnych'. Więc sprowadza się to do formy zastrzyku zależności. –

2

można po prostu użyć dobrych staroświeckich zasad OO, np.

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

Kod powinien dostać odwołanie do realizacji TimeService poprzez wstrzyknięcie zależności. W resources.groovy użyć MockTimeService tylko podczas uruchamiania testów

import grails.util.Environment 

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

    } else { 
     timeService(JodaTimeService) 
    } 
} 
+0

Niezależnie od tego samego podejścia co powyżej, bardzo dziękuję i dobre rozwiązanie zostało dogłębnie przeanalizowane. Dodatkowo dziękuję za wskazówki dotyczące używania środowiska testowego do przełączania. –

18

Wiem, że zostało to już zaakceptowane, ale dzięki Joda-time możesz zamrozić i ustawić to, co chcesz. Możesz więc zamrozić czas, czas wyprzedzenia, cofnąć się w czasie. Pod warunkiem, że konsekwentnie używasz Jody, twoje obiekty otrzymają "teraz", niezależnie od tego, kiedy je ustawisz.

// 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 schludny, miałem nadzieję na coś takiego. To znacznie ułatwi testowanie. Świetna rada !! –

+0

Teraz czuję się głupio, ponieważ jesteśmy na Jodzie. To lepszy sposób. Dobrze, nauczyłem się czegoś. –