2010-12-15 75 views
20

我想測試這種方法:如何模擬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(); 
} 

但我需要DateTime().year().get()DateTime().dayOfMonth().get()總是返回相同的日期

TKS

回答

48

如果您無法按照skaffman的建議添加工廠對象,則可以使用DateTimeUtils.setCurrentMillisFixed()

+7

評論真好,我想兩次。 – 2012-05-16 00:19:29

+5

也許你會想在測試斷言後用'setCurrentMillisSystem'將它重置回系統。 – 2014-03-18 06:19:25

+6

該API修改了全局變量,因此必須避免。 – 2014-08-02 15:59:56

14

然後,你需要定義一個Clock接口,並注入到您的班級

public interface Clock { 
    DateTime getCurrentDateTime(); 
} 

then:

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

然後,您的測試可以注入執行Clock(例如,使用模擬框架)總是返回一個固定的時間。

我使用Clock接口很多我自己的東西,我仍然感到驚訝,它不是其中一個共同的圖書館的一部分。我有兩個實現我使用了很多,WallClockStoppedClock(這對於使用固定時間的測試非常有用)。

+0

我喜歡你的想法。但我有夫妻問題,我想問。 'Clock#getCurrentDateTime()'會返回當前的'JodaTime#DateTime',這非常棒。不過,我需要將當前的DateTime與美國東部時間下午4點進行比較。在我的代碼中,我有這個'fourPM = new DateTime(current.getYear(),current.getMonthOfYear(), \t \t \t \t current.getDayOfMonth(),16,0,0,0,DateTimeZone.forID 「));'for'current = new DateTime()' – 2011-05-18 18:00:52

+0

@Harry:您需要提出一個新問題 – skaffman 2011-05-18 18:04:17

+0

我剛剛創建了一個新問題。 http://stackoverflow.com/questions/6049777/mockito-how-to-mock-an-interface-of-jodatime請幫忙 – 2011-05-18 19:05:59

1

這很容易,如果使用的是JMockit期望嘲諷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擅長測試寫得不好的代碼。 – IAdapter 2010-12-16 19:35:25

+0

因此,使用'DateTime'(或'java.util.Date')這樣的代碼總是不好?使用Apache Commons Email API的代碼怎麼樣,它實例化一個SimpleEmail對象並在其上調用send()?它是不好的代碼?爲什麼? – 2010-12-17 18:41:49

4

貌似唯一的選擇是使用應答功能發佈此評論:

代碼的以下部分可導致到難以檢測錯誤:

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

讓我們假設塔今天是2011年的最後一天,這部分代碼被稱爲納米1秒在新的一年之前,第一個聲明需要超過1納秒才能完成。這意味着,今年將設定爲2011年,但月份爲1,但最好到2011/12或2012/1。

雖然在統計上是非常不可能發生的,但在邏輯上有可能發生:)

您應該創建一個DateTime實例,並用它來填充兩個yearmonth

+1

好吧,這不是OP的答案,但我贊成它,因爲更多的人需要意識到這個問題。 鑑於許多企業商店(和家庭設置)在晚上的下班時間(如下午11:30)進行編譯,這個錯誤實際上非常普遍 - 並且很煩人。它通常更加微妙,但這就是爲什麼在另一個答案中提到的StoppedClock是一個好主意。 – 2012-05-16 00:18:05