2012-02-23 75 views
8

我有一種方法,根據當前日期是從數據庫中獲取的數據實現不同的邏輯。Java中的單元測試基於時間的邏輯

我想通過讓單元測試創​​建對象並將它們保存在數據庫中並調用測試方法來測試它。但是,爲了獲得可預測的結果,我需要每次更改系統日期,並且我不知道如何在Java中執行此操作。

對此提出建議?

+2

改變你的方法,這樣你的確可以把時間作爲參數,那麼你可以通過給你任何你想要的時間來測試它。這又是什麼話? – belgther 2012-02-23 09:19:26

+0

你能告訴你如何得到當前的日期和時間?也許嘲笑會起作用... – 2012-02-23 09:22:15

+0

現在只需用'new Date()',也許我需要一個TimeProvider類 – Alex 2012-02-23 09:43:41

回答

14

您可以使用當前日期生成您的預期結果。

或者你編寫你的系統使用測試時的日期/時間(而不是時鐘)這樣的時間總是測試期望的。

我使用類似

interface TimeSource { 
    long currentTimeMS(); // actually I have currentTimeNS 
    void currentTimeMS(long currentTimeMS); 
} 

enum VanillaTimeSource implements TimeSource { 
    INSTANCE; 

    @Override 
    public long currentTimeMS() { 
     return System.currentTimeMillis(); 
    } 

    @Override 
    public void currentTimeMS(long currentTimeMS) { 
     // ignored 
    } 
} 

class FixedTimeSource implements TimeSource { 
    private long currentTimeMS; 
    @Override 
    public long currentTimeMS() { 
     return currentTimeMS; 
    } 

    @Override 
    public void currentTimeMS(long currentTimeMS) { 
     this.currentTimeMS =    currentTimeMS; 
    } 
} 

在測試中,我使用能夠數據例如被驅動FixedTimeSource由輸入/事件設置。在生產中,我使用VanillaTimeSource.INSTANCE,它忽略輸入/事件中的時間並使用當前時間。

+0

第一個建議可能贏了沒有工作。我也應該提到,準確提取的數據也是基於日期(根據某一列)。這意味着即使邏輯沒有什麼不同,我也不得不根據一年中的每一天生成不同的結果。我可能會提出第二個建議 – Alex 2012-02-23 09:32:03

+0

在檢查結果之前,您可以生成預期結果作爲運行測試的一部分。你不需要提前生成它們。 – 2012-02-23 09:34:11

+0

實際上,將接收時間的類/組件作爲參數確保它是一個很好的組件,因爲它可以從系統時間中解耦。您將所有應用程序特定的配置(「使用系統時間」)放在組件外。它只需要依靠外部可配置的刺激。 – helios 2012-02-23 09:46:27

8

你需要注意在你的課堂上注入一些東西,讓你可以自定義時間的呈現方式。

例如

public interface TimeProvider { 
    DateTime getCurrentTime(); 
} 

public class UnderTest { 

    // Inject this in some way (e.g. provide it in the constructor) 
    private TimeProvider timeProvider; 

    public void MyMethod() { 
    if (timeProvider.getCurrentTime() == "1234") { 
     // Do something 
    } 
    } 
} 

現在在單元測試中,你可以提供假的實施時間提供商。在實際生產代碼中,您可以返回當前日期時間。

+0

當然,你也可以提供它作爲'belgther'建議的參數:) – 2012-02-23 09:20:52

2

最近我有一個類似的問題,我無法重構代碼太多(時間限制,不想無意間破壞任何東西)。它有一個我想測試的方法,稱爲System.currentTimeMillis(),我想測試的情況取決於返回的值。喜歡的東西:

public class ClassINeedToTest { 
    public boolean doStuff() { 
     long l = System.currentTimeMillis(); 
     // do some calculation based on l 
     // and return the calculation 
    } 
} 

爲了讓單元測試,我重構了類,所以它有其保護

protected long getCurrentTimeMillis() { 
    // only for unit-testing purposes 
    return System.currentTimeMillis(); 
} 

一個輔助方法,該方法是由doStuff稱爲()。這並沒有改變的功能,但現在的意思是,當我把它的單元測試,然後我可以重寫此方法以返回一個特定的值,例如

ClassINeedToTest testClass = new ClassINeedToTest() { 
    protected long getCurrentTimeMillis() { 
     // return specific date for my test 
     return 12456778L; 
    } 
}; 
boolean result = testClass.doStuff(); 
// test result with an assert here 

然而,這意味着我已經污染了我的班級的界面,所以你可能會決定成本太高。如果你可以更多地重構代碼,可能會有更好的方法。