2016-01-05 66 views
1

我試圖測試一個計算年齡的類。計算年齡的方法是這樣的:Java Mockito何時返回創建對象

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

因爲我想了JUnit是時間無關我想today變量始終是2016年1月1日,爲了做到這一點,我試圖去了Mockito.when路線,但我遇到了麻煩。

我第一次有這樣的:

public class CalculatorTest { 

    @Before 
    public void setUp() throws Exception { 
     LocalDate today = new LocalDate(2016,1,1); 

     Mockito.when(new LocalDate()).thenReturn(today); 
    } 
} 

但是到我得到這個錯誤:

org.mockito.exceptions.misusing.MissingMethodInvocationException: 
when() requires an argument which has to be 'a method call on a mock'. 
For example: 
    when(mock.getArticles()).thenReturn(articles); 

Also, this error might show up because: 
1. you stub either of: final/private/equals()/hashCode() methods. 
    Those methods *cannot* be stubbed/verified. 
    Mocking methods declared on non-public parent classes is not supported. 
2. inside when() you don't call method on mock but on some other object. 

於是我試圖讓計算器類中的方法返回當前的日期,像這樣:

public static LocalDate getCurrentDate() { 
    return new LocalDate(); 
} 

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

,這樣我可以做到這一點:

public class CalculatorTest { 

    @Before 
    public void setUp() throws Exception { 
     CalculatorTest mock = Mockito.mock(CalculatorTest.class); 
     LocalDate today = new LocalDate(2016,1,1); 

     Mockito.when(mock.getCurrentDate()).thenReturn(today); 
    } 
} 

但是,我得到了完全相同的問題。那麼,有關如何在觸發年齡計算時返回預定義的本地對象的任何想法?

+2

你試過從'getCurrentDate'刪除'static'修改? Mockito不能模擬靜態方法。 – user3707125

回答

4

而不是嘲笑,我建議使用喬達的DateTimeUtils來「凍結」時間。您還需要在應用程序代碼中使用org.joda.time.LocalDate而不是java.time.LocalDate

public class CalculatorTest { 

    @Before 
    public void setUp() throws Exception { 
     DateTimeUtils.setCurrentMillisFixed(new LocalDate(2016,1,1).toDateTimeAtStartOfDay().getMillis()); 
    } 

    @After 
    public void tearDown() { 
     DateTimeUtils.setCurrentMillisSystem(); 
    } 
} 

對於純Java,可以考慮一些方法描述here,具體地,注入Clock或使用PowerMock。

注入Clock與Joda示例非常相似;你只需要保持自己的靜態Clock。您的應用程序代碼應該是這樣的:

static Clock appClock = Clock.systemDefaultZone(); 

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

並且測試將凍結這樣的時候:

public class CalculatorTest { 

    @Before 
    public void setUp() { 
     appClock = Clock.fixed(LocalDate(2016,1,1).toDateTimeAtStartOfDay(), ZoneId.systemDefault()); 
    } 

    @After 
    public void tearDown() { 
     appClock = Clock.systemDefaultZone(); 
    } 
} 
+0

DateMidnight已棄用,我應該使用LocalDate嗎? – Richard

+0

@Richard你是否想過[toDateTimeAtMidnight](http://joda-time.sourceforge.net/apidocs/org/joda/time/LocalDate.html#toDateTimeAtMidnight())? –

+0

不,我試過'DateMidnight'和intelliJ說它的棄用。 – Richard

0

我八方通用我自己的TimeFactory來檢索我的應用程序的currentdate。這樣我可以靈活地操作它(在JUnit測試期間)。這就是TimeFactory樣子:

public final class TimeFactory { 

    static int offsetAmount = 0; 
    static TemporalUnit offsetUnit = ChronoUnit.MILLIS; 

    public static LocalDateTime getLocalDateTimeNow() { 
     return LocalDateTime.now().plus(offsetAmount, offsetUnit); 
    } 

    public static void reset() { 
     offsetAmount = 0; 
    } 

    public static void travelToPast(int amount, TemporalUnit unit) { 
     offsetAmount = amount * -1; 
     offsetUnit = unit; 
    } 

    public static void travelToFuture(int amount, TemporalUnit unit) { 
     offsetAmount = amount; 
     offsetUnit = unit; 
    } 
} 

使用這個TimeFactory我可以很容易做到時間旅行:

// start test 
TimeFactory.travelToPast(10, ChronoUnit.HOURS); 
// continue tests 
TimeFactory.reset(); 
// check that things have happend in the past. 

可以擴大這個代碼來解決的時間。

1

我建議你欺騙到測試方法:

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

public static int getAge(LocalDate birthdate) { 
    return getAge(new LocalDate(), birthdate); 
}