2010-02-17 43 views
7

我有這種依賴於當前日期的方法。它會檢查今天是星期一,星期一,星期二或星期三,然後提供5天的貨物到貨時間。如果星期四,星期五或星期六,則提供6天的交貨時間來計入週末。如何測試依賴於當前日期的邏輯

private DateTime GetEstimatedArrivalDate() 
{ 
    DateTime estimatedDate; 
    if (DateTime.Now.DayOfWeek >= DayOfWeek.Thursday) 
    { 
     estimatedDate = DateTime.Now.Date.AddDays(6); 
    } 
    else 
    { 
     estimatedDate = DateTime.Now.Date.AddDays(5); 
    } 
    return estimatedDate; 
} 

實際的估計邏輯比較複雜。爲了這個問題,我簡化了它。我的問題是如何爲這樣的事情編寫一個單元測試,這取決於今天的日期?

+0

答案是(幾乎)中的問題「我如何爲這樣的事情寫一個單元測試,取決於今天的日期?」在Mark的答案中重構使用依賴注入的方法。 – 2010-02-17 21:35:28

回答

17

您需要在傳遞當前日期作爲參數:

private DateTime GetEstimatedArrivalDate(DateTime currentDate) 
{ 
    DateTime estimatedDate; 
    if (currentDate.DayOfWeek >= DayOfWeek.Thursday) 
    { 
     estimatedDate = currentDate.AddDays(6); 
    } 
    else 
    { 
     estimatedDate = currentDate.AddDays(5); 
    } 
    return estimatedDate; 
} 

在真正的代碼,你這樣稱呼它:

DateTime estimatedDate = GetEstimatedArrivalDate(DateTime.Now.Date); 

然後你就可以進行測試如下:

DateTime actual = GetEstimatedArrivalDate(new DateTime(2010, 2, 10)); 
DateTime expected = ...; 
// etc... 

注意,這還修復程序中的一個潛在問題,其中連續調用之間的日期改變。

+0

我剛剛發佈了相同的答案。你擊敗了我的速度:) – Romain 2010-02-17 20:55:07

+0

固定如果你。 – 2010-02-17 20:57:30

+1

+1最後一行...... – 2010-02-17 21:05:06

0

似乎有足夠的案例數量,你可以明確地測試它們。該方法取決於今天的日期,但輸出僅取決於星期幾,並且每個日期都有一個星期幾。

0

基礎上,你可以通過在正常執行期間返回DateTime.Now一個委託,然後在您的測試通過在返回一個固定的日期另一位代表,並斷言你的結果。

0

一個「共同」這樣做的方式是「假的」當前系統日期(可以以多種方式進行),然後測試的「已知的」日期代碼。

另一個有趣的方式是稍微改變你的實現:

private DateTime GetEstimatedArrivalDate() 
{ 
    return GetEstimatedArrivalDate(DateTime.Now); 
} 

private DateTime GetEstimatedArrivalDate(DateTime forDate) 
{ 
    DateTime estimatedDate; 
    if (forDate.DayOfWeek >= DayOfWeek.Thursday) 
    { 
     estimatedDate = forDate.Date.AddDays(6); 
    } 
    else 
    { 
     estimatedDate = forDate.Date.AddDays(5); 
    } 
    return estimatedDate; 
} 

然後使用方法與參數,以測試「立竿見影」的日期。

1

我會給出有爭議的答案,不要測試它。

的邏輯是微不足道的,它具有零個依存關係,相信在良好的代碼覆蓋率而不是在它沒有真正的收益增加了複雜性。

+1

這聽起來很合理,但這正是我期望意外改變的那種方法。如果公司更改其運輸政策,開始提供分層服務或交換運營商。從技術上講,一旦變得複雜,你可以開始測試它,但我傾向於認爲這是應用程序中的一個重要變化,它應該在測試中,以便絕對每個人都知道它發生變化的時刻。以防萬一。 – jcdyer 2010-02-17 20:59:47

+0

Bah。如果我們決定在周內交換星期四和星期五的頭寸,該怎麼辦?你永遠不會知道這段代碼被打破了,直到它太遲了!如果我們決定開始計算日子*倒退*,那麼,我甚至不知道*如果你能夠告訴你什麼*不會讓我看到閃爍的紅色「測試失敗」燈。 ;) – Aaronaught 2010-02-17 21:05:50

+0

我同意其他評論者。這種方法中的邏輯實際上是非trival。我只是爲了將它作爲我的問題的一個例子而簡化它。我確實想徹底測試它。 – 2010-02-17 23:28:14

9

一般來說,你會希望抽象獲取當前日期和時間的界面背後的方法,如:

public interface IDateTimeProvider 
{ 
    DateTime Now { get; } 
} 

真正的服務是:

public class DateTimeProvider: IDateTimeProvider 
{ 
    public DateTime Now 
    { 
     get 
     { 
      return DateTime.Now; 
     } 
    } 
} 

而且一測試服務將是:

public class TestDateTimeProvider: IDateTimeProvider 
{ 
    private DateTime timeToProvide; 
    public TestDateTimeProvider(DateTime timeToProvide) 
    { 
     this.timeToProvide = timeToProvide; 
    } 

    public DateTime Now 
    { 
     get 
     { 
      return timeToProvide; 
     } 
    } 
} 

對於需要當前時間的服務,讓他們接受一個I​​Da teTimeProvider作爲依賴項。對於真實情況,傳遞一個新的DateTimeProvider();當你是一個組件時,傳入一個新的TestDateTimeProvider(timeToTestFor)。

+1

我會給你一個+ 1,因爲你絕對正確,但同時我覺得它僅僅是測試一個trival方法而已。我很欽佩你對覆蓋的貢獻,而且如果有很多方法或需要測試的複雜方法,我可能會採用這種方式。) – 2010-02-17 21:03:14

+0

現在這可能是微不足道的,但事情很容易改變。無論如何,+1,因爲我肯定會在DateTime類中做一個適配器來啓用測試。另外,對於TDDer來說,這將是正常的路線。 – Finglas 2010-02-17 21:28:25

+0

請注意,使用模擬框架不是更好,而不是創建一個您現在需要維護的「測試服務」。這似乎有點不通俗? – 2010-02-17 21:53:55

2

使類採取IClock參數(通過構造函數或屬性)

interface IClock 
{ 
    DateTime Now { get; } 
} 

然後,您可以使用一個假的實施測試

class FakeClock : IClock 
{ 
    DateTime Now { get; set } 
} 

和真正實施的時間休息。

class SystemClock : IClock 
{ 
    DateTime Now { get { return DateTime.Now; } } 
} 
0

我建議這樣做是Mark suggests,但增加了一個重載的呼叫在生產中使用的,它沒有任何參數,並使用DateTime.Now

private DateTime GetEstimatedArrivalDate() 
{ 
    return GetEstimatedArrivalDate(DateTime.Now); 
} 

private DateTime GetEstimatedArrivalDate(DateTime currentDate) 
{ 
    DateTime estimatedDate; 
    if (currentDate.DayOfWeek >= DayOfWeek.Thursday) 
    { 
     estimatedDate = currentDate.AddDays(6); 
    } 
    else 
    { 
     estimatedDate = currentDate.AddDays(5); 
    } 
    return estimatedDate; 
}