2016-01-05 44 views
3

我曾與1種方法的Util類使用喬達時,其計算年齡:與時間無關的JUnit測試案例

public static int getAge(LocalDate birthdate) { 
    LocalDate today = new LocalDate(); 
    Period period = new Period(birthdate, today, PeriodType.yearMonthDay()); 
    return period.getYears(); 
} 

我已經寫了廣泛的JUnit測試類,但我怎麼讓它與時間無關?如果我創建一個測試用例來計算某人的年齡,如果他們今天出生於1970年,那麼結果將是46歲。但是從現在開始1年,如果我運行測試用例,它將會失敗,因爲結果將會是47.

那麼,如何使這些測試用例與時間無關。我正在考慮有某種日曆界面,測試用例會從中創建日期對象。我也偶然發現this這是另一個可能的解決方案,但我不確定如何去解決這個問題。

回答

2

使用固定日期:

LocalDate today = new LocalDate(2016, 1, 5); 
+0

哇....我不知道爲什麼我沒有想到這個......最明顯的解決方案......謝謝 – Richard

+1

np。你可以接受答案:-) – mks

+0

實際上,現在我無法正常工作,因爲'new LocalDate'在getAge函數內部,我無法在其中硬編碼值。它必須是生產使用中的當前日期。所以我想知道是否有某種方法可以用'Mockito.when'代替' – Richard

4

通常的做法(在書中以成長導向的測試面向對象軟件的描述)是委託創建日期實例的合作者的責任。

想象一下,你有一個這樣的類:

public class Clock { 
    public LocaleDate now(){ 
    return new LocalDate(); 
    } 
} 

那麼你的代碼將變得

public static int getAge(LocalDate birthdate, Clock clock) { 
    LocalDate today = clock.now(); 
    Period period = new Period(birthdate, today, PeriodType.yearMonthDay()); 
    return period.getYears(); 
} 

我會被罰款不測試Clock#now,因爲它是平凡正確的,但現在我可以傳遞一個模擬時鐘實例來測試getAge方法。

現在這意味着一個類使用靜態getAge必須提供一個時鐘,時鐘將是這個類的依賴。這種依賴關係可以以各種可嘲弄的方式注入。

我個人是injection by constructor學校,但是從injection by reflection到proctected工廠方法(因此可以在用於創建測試實例的匿名子類中重載)的任何工作。

此問題而設計,我建議在長度the book討論,在很多blog postsstack overflow(它看起來像Java 8具有direct support它,如果你願意搬到java.time)

1

所以,首先讓我說我同意Jean。不過,我發現這種模式非常普遍,我在GitHub的庫中實現了一個名爲LibEx的可重用解決方案。它被稱爲DateSupplier。要獲得當前的DateTime,請使用DateSupplier.getCurrentDateTime()。然後在測試中使用允許datController.setCurrentDateTo...()@Rule DateController。在測試中設置此項時,DateSupplier將返回DateController指定的值。

這裏是鏈接:然後

您的測試應該是這樣..

public class DateControllerTest extends TestBase { 

@Rule 
public DateController dateContoller = new DateController(); 

@Test 
public void testSetCurrentTime() { 
    // setup 
    Date date = new Date(123443); 

    // test 
    dateContoller.setCurrentTime(date); 

    // verify 
    assertDateEquals(date); 
} 

private void assertDateEquals(Date date) { 
    assertThat(DateSupplier.getCurrentDate(), equalTo(date)); 
    assertThat(DateSupplier.getCurrentDateInMilliseconds(), equalTo(date.getTime())); 
} 

因爲DateControllerRule,它會重置爲每次測試後的默認行爲。此外,DateController位於libex-test模塊中,該模塊應該是測試範圍,因此它已部署在生產代碼中。

-1

所以你想要今天有人轉身46的生日? (你的問題是不明確的。)

java.time

喬達時間的製造商告訴我們,移動到使用java.time框架構建在Java 8和以後只要是舒服。

ZonedDateTime birthdateOf46YearOld = ZonedDateTime.now().minusYears(46); 

該對象被隱式分配給JVM的當前默認時區。我建議您始終明確您的時區。

ZoneId zoneId = ZoneId.of("America/Montreal"); // Or… ZoneOffset.UTC …or… ZoneId.systemDefault(). 
ZonedDateTime birthdateOf46YearOld = ZonedDateTime.now(zoneId).minusYears(46); 

或者你想測試一個日期時間值是否與出生日期相同?

Boolean hit = someZdt.isEqual(birthdateOf46YearOld); 

如果你只關心日期沒有時間的日或時區,然後用LocalDate,類似於喬達時間。請注意,時區對於確定今天的日期至關重要,因爲它在全球各個時區都有所不同。

LocalDate birthdate = LocalDate.now(zoneId).minusYears(46) ; 

如果你只是想在一對LOCALDATE的對象之間的年經過的時間,使用Period類。

LocalDate today = LocalDate.now(zoneId); 
LocalDate birthDate = … ; 
Period period = Period.between(birthDate , today); 
Integer ageInYears = period.getYears(); 
Boolean hit = ageInYears.equals (Integer.valueOf(46)) ;  

喬達時間

如果你的Java 8或更高版本不提供給你,相同類型的代碼喬達時間工作。

DateTimeZone zone = DateTimeZone.forID("America/Montreal"); 
DateTime birthdate = DateTime.now(zone).minusYears(46); 
+0

親愛的下來選民:請隨着你的投票批評。 –