2012-02-14 105 views
20

在我的代碼,我有這樣的事情:java:如何模擬Calendar.getInstance()?

private void doSomething() { 
    Calendar today = Calendar.getInstance(); 
    .... 
} 

我怎麼能「模擬」它在我的JUnit測試返回的具體日期?

+1

這條線不能被編譯! – adarshr 2012-02-14 11:12:39

+0

「今天」是方法內的類成員(字段)還是局部變量? – 2012-02-14 11:15:01

+0

方法內的局部變量 – Randomize 2012-02-14 11:17:21

回答

14

據我看到它,你有三個合理的選擇:

  1. 注入的任何方法/類,你設定的那一天在Calendar實例。

    private void method(final Calendar cal) { Date today = cal.getTime(); }

  2. 使用JodaTime而不是Calendar。這不是一種選擇,更多的是一種建議,因爲JodaTime會讓你的生活變得更輕鬆。您仍然需要將這段時間注入方法。

    DateTime dt = new DateTime();

    Date jdkDate = dt.toDate();

  3. Calendar一些接口,可以讓你獲取的時間內。然後,你只是嘲笑該接口,並讓它返回一個常量Date

    Date today = calendarInterfaceInstance.getCurrentDate()

+3

Joda Time的DateTimeUtils類具有設置所有其他Joda Time對象的當前時間的靜態方法。這對於將時間設置到特定時刻非常有用,例如用於測試。 – Jesper 2012-02-14 12:16:05

+0

@Jesper - 是的,這是真的,我忽略了一個好點 – BeRecursive 2012-02-14 12:26:11

+1

謝謝你們。我遵循你的建議,並轉移到JodaTime。順便說一句,它很容易修復類似這樣的問題:DateTimeUtils.setCurrentMillisFixed(new DateTime(2012,2,14,13,43,21).getMillis()); – Randomize 2012-02-14 14:48:13

9

不要嘲笑它 - 而是引入一種方法,你可以模擬獲取日期。事情是這樣的:

interface Utility { 

    Date getDate(); 
} 

Utilities implements Utility { 


    public Date getDate() { 

     return Calendar.getInstance().getTime(); 
    } 

} 

然後你可以注入到這個類或只使用一個輔助類有一堆的靜態方法與接口的負載方法:

public class AppUtil { 

    private static Utility util = new Utilities(); 

    public static void load(Utility newUtil) { 

     this.util = newUtil; 
    } 

    public static Date getDate() { 

     return util.getDate(); 
    } 

} 

然後在您的應用程序代碼:

private void doSomething() { 
    Date today = AppUtil.getDate(); 
    .... 
} 

然後你可以在你的測試方法中加載一個模擬接口。

@Test 
public void shouldDoSomethingUseful() { 
    Utility mockUtility = // .. create mock here 
    AppUtil.load(mockUtility); 

    // .. set up your expectations 

    // exercise the functionality 
    classUnderTest.doSomethingViaAPI(); 

    // ... maybe assert something 

} 

又見Should you only mock types you own?Test smell - everything is mocked

2

編寫一個叫做DateHelper類的方法getCalendar返回Calendar.getInstance()。重構您正在測試的類,以便它具有DateHelper類型的成員變量以及注入該成員變量的構造函數。在您的測試中使用該構造函數,注入DateHelper的模擬,其中getCalendar已被樁接以返回某個已知日期。

9

可以組合使用PowerMock用的Mockito嘲笑它:

在類的頂部:

@RunWith(PowerMockRunner.class) 
@PrepareForTest({ClassThatCallsTheCalendar.class}) 

成功的關鍵是,你必須把這個類,你在PrepareForTest使用日曆而不是日曆本身,因爲它是一個系統類。 (我曾經親自到搜索了很多,我發現這個之前)

然後嘲諷自己:

mockStatic(Calendar.class); 
when(Calendar.getInstance()).thenReturn(calendar); 
+0

你包含哪些依賴以獲得mockStatic()方法的工作? – 2017-03-13 15:18:50

+0

對不起,我應該這麼說。我使用import static來導入PowerMockito的mockStatic方法。請參閱powermock mockito的此依賴關係:http://mvnrepository.com/artifact/org.powermock/powermock-api-mockito2/1.6.6 – GoGoris 2017-03-14 19:01:21

6

使用的Mockito和PowerMockito:

Calendar endOfMarch = Calendar.getInstance(); 
endOfMarch.set(2011, Calendar.MARCH, 27); 
PowerMockito.mockStatic(Calendar.class); 
Mockito.when(Calendar.getInstance()).thenReturn(endOfMarch); 

參考link完整的代碼。

0

對於那些誰遵循MVP模式嘲諷日曆是小菜一碟:

  1. 在演示創建返回日曆實例的方法:

    public Calendar getCurrentTime() { 
         return Calendar.getInstance();  
        } 
    
  2. 在您看來(活動,片段等)您可以在演示者的幫助下訪問日曆:

    Calendar calendar = mPresenter.getCurrentTime(); 
    // do whatever you want 
    
  3. 在你的測試,你做的事:

    // create a dummy calendar 
    Calendar mockCalendar = ... 
    // You've already mocked your Presenter, haven't you? 
    when(mMockPresenter.getCurrentTime()).thenReturn(mockCalendar); 
    // here you are!