2010-12-15 14 views
20

Chcę przetestować tę metodę:Jak mogę sfałszować faktyczną datę JodaTime?

public FirmOrder findActiveByModelColor(ModelColor modelColor) { 
    Query query = em.createQuery("FROM FirmOrder fo WHERE fo.modelColor = :modelColor AND fo.year = :year AND fo.month = :month"); 
    query.setParameter("modelColor", modelColor); 
    query.setParameter("year", new DateTime().year().get()); 
    query.setParameter("month", new DateTime().monthOfYear().get()); 
    return (FirmOrder) query.getSingleResult(); 
} 

ale muszę DateTime().year().get() i DateTime().dayOfMonth().get() zawsze wrócić tego samego dnia

TKS

Odpowiedz

48

Jeśli nie możesz dodać obiektu fabrycznego zgodnie z sugestią użytkownika skaffman, możesz użyć DateTimeUtils.setCurrentMillisFixed().

+7

Komentarz tak miły, chcę go dwa razy. –

+5

Być może będziesz chciał zresetować go do systemu za pomocą 'setCurrentMillisSystem' po swoich asercji testowych. –

+6

Ten interfejs API modyfikuje zmienną globalną i dlatego należy jej unikać. –

14

Następnie trzeba zdefiniować interfejs Clock i wstrzyknąć go do klasa

public interface Clock { 
    DateTime getCurrentDateTime(); 
} 

następnie:

Clock clock; 

public FirmOrder findActiveByModelColor(ModelColor modelColor) { 
    Query query = em.createQuery("FROM FirmOrder fo WHERE fo.modelColor = :modelColor AND fo.year = :year AND fo.month = :month"); 
    query.setParameter("modelColor", modelColor); 
    query.setParameter("year", clock.getCurrentDateTime().year().get()); 
    query.setParameter("month", clock.getCurrentDateTime().dayOfMonth().get()); 
    return (FirmOrder) query.getSingleResult(); 
} 

Twój test może następnie wprowadzić implementację Clock (np. za pomocą szyderczego frameworka), który zawsze zwraca ustalony czas.

Używam interfejsu Clock w moich własnych rzeczach i nadal jestem zaskoczony, że nie należy on do jednej z popularnych bibliotek. Mam dwie implementacje, których często używam, WallClock i StoppedClock (co jest przydatne w testach wykorzystujących ustalony czas).

+0

Podoba mi się twój pomysł. Ale mam pytania o pary, które chcę zadać. 'Clock # getCurrentDateTime()' zwróci mi bieżące 'JodaTime # DateTime', co jest świetne. Jednak muszę porównać bieżący DateTime do 4PM EST. W moim kodu, mam ten 'fourPM = new DateTime (current.getYear(), current.getMonthOfYear(), \t \t \t \t current.getDayOfMonth(), 16, 0, 0, 0, DateTimeZone.forID (" EST "));' dla 'current = new DateTime()' –

+0

@Harry: Musisz zadać nowe pytanie – skaffman

+0

Po prostu utworzę nowe pytanie. http://stackoverflow.com/questions/6049777/mockito-how-to-mock-an-interface-of-jodatime Proszę o pomoc –

1

To proste, jeśli za pomocą JMockit Oczekiwania szyderczy API:

@Test 
public void findActiveByModelColor() 
{ 
    new NonStrictExpectations() 
    { 
     @Cascading DateTime dt; 

     { 
      dt.year().get(); result = 2010; 
      dt.monthOfYear().get(); result = 12; 
     } 
    }; 

    FirmOrder fo = testedObject.findActiveByModelColor(modelColor); 

    // asserts... 
} 
+1

JMockit świetnie sprawdza się przy testowaniu źle napisanego kodu. – IAdapter

+0

Tak, kod, który używa 'DateTime' (lub' java.util.Date') w ten sposób jest zawsze zły? A co z kodem korzystającym z API Apache Commons Email, który tworzy instancję obiektu 'SimpleEmail' i wywołuje na niej' send() '? Czy to zły kod? Czemu? –

4

Wygląda na to, że jedynym rozwiązaniem jest skorzystanie z funkcji odbierania zamieścić ten komentarz:

Poniższy fragment kodu może prowadzić do trudnych do wykrycia błędów:

query.setParameter("year", new DateTime().year().get()); 
query.setParameter("month", new DateTime().monthOfYear().get()); 

Udawajmy tha dzisiaj jest ostatni dzień roku 2011 i ta część kodu jest nazywany 1 nanosekunda przed nowym rokiem, a pierwsze oświadczenie zajmuje więcej niż 1 nano sekundy. Oznacza to, że rok zostanie ustawiony na 2011 r., Ale miesiąc na 1, ale musi być najlepszy do roku 2011/12 lub 2012/1.

Mimo że statystycznie jest to bardzo mało prawdopodobne, ale logicznie może się zdarzyć :)

Należy utworzyć jedną instancję DateTime i używać, aby wypełnić oba year i month.

+1

Okay, to nie jest odpowiedź na PO, ale przegłosowałem to, ponieważ więcej ludzi musi być świadomych tego problemu. Biorąc pod uwagę, że wiele sklepów firmowych (i domowych) robi kompilację podczas poza godzinami nocy (np. 23:30), ten błąd jest rzeczywiście zaskakująco popularny - i denerwujący. Zwykle jest bardziej subtelny, ale właśnie dlatego wspomniany w innej odpowiedzi StoppedClock jest dobrym pomysłem. –

Powiązane problemy