簡體   English   中英

時間相關單元測試

[英]Time dependent unit tests

我需要測試一個函數,其結果將取決於當前時間(使用 Joda 時間的isBeforeNow() ,它發生了)。

public boolean isAvailable() {
    return (this.someDate.isBeforeNow());
}

是否可以使用(例如,使用 Mockito)存根/模擬系統時間,以便我可以可靠地測試該功能?

使您的代碼可測試的最佳方法 (IMO) 是將“當前時間是什么”的依賴關系提取到其自己的接口中,並使用使用當前系統時間(正常使用)的實現和允許您設置時間的實現,根據需要推進它等。

我在各種情況下都使用過這種方法,而且效果很好。 它很容易設置 - 只需創建一個界面(例如Clock ),該界面具有單一方法,可以以您想要的任何格式(例如使用 Joda Time 或可能的Date )為您提供當前時刻。

Joda 時間支持通過DateTimeUtils類的setCurrentMillisFixedsetCurrentMillisOffset方法設置“假”當前時間。

https://www.joda.org/joda-time/apidocs/org/joda/time/DateTimeUtils.html

Java 8 引入了抽象類java.time.Clock ,它允許您有一個替代的測試實現。 這正是喬恩當時在他的回答中所建議的。

要添加到Jon Skeet 的答案中,Joda Time 已經包含一個當前時間接口: DateTimeUtils.MillisProvider

例如:

import org.joda.time.DateTime;
import org.joda.time.DateTimeUtils.MillisProvider;

public class Check {
    private final MillisProvider millisProvider;
    private final DateTime someDate;

    public Check(MillisProvider millisProvider, DateTime someDate) {
        this.millisProvider = millisProvider;
        this.someDate = someDate;
    }

    public boolean isAvailable() {
        long now = millisProvider.getMillis();
        return (someDate.isBefore(now));
    }
}

在單元測試中模擬時間(使用Mockito,但您可以實現自己的類 MillisProviderMock):

DateTime fakeNow = new DateTime(2016, DateTimeConstants.MARCH, 28, 9, 10);
MillisProvider mockMillisProvider = mock(MillisProvider.class);
when(mockMillisProvider.getMillis()).thenReturn(fakeNow.getMillis());

Check check = new Check(mockMillisProvider, someDate);

在生產中使用當前時間( DateTimeUtils.SYSTEM_MILLIS_PROVIDER在 2.9.3 中被添加到 Joda 時間):

Check check = new Check(DateTimeUtils.SYSTEM_MILLIS_PROVIDER, someDate);

我使用了一種類似於 Jon 的方法,但不是只為當前時間創建一個專門的接口(比如Clock ),我通常創建一個特殊的測試接口(比如MockupFactory )。 我把測試代碼所需的所有方法都放在那里。 例如,在我的一個項目中,我有四種方法:

  • 一個返回一個模型數據庫客戶端;
  • 創建一個模型通知程序對象,通知代碼有關數據庫中的更改;
  • 創建一個模型 java.util.Timer 在我想要的時候運行任務;
  • 一個返回當前時間。

被測試的類有一個構造函數,它在其他參數中接受這個接口。 沒有這個參數的只是創建了這個界面的一個默認實例,它可以“在現實生活中”工作。 接口和構造函數都是包私有的,因此測試 API 不會泄漏到包之外。

如果我需要更多模仿對象,我只需向該接口添加一個方法並在測試和實際實現中實現它。

通過這種方式,我首先設計了適合測試的代碼,而不會對代碼本身施加太多影響。 事實上,由於大量的工廠代碼集中在一個地方,因此代碼變得更加清晰。 例如,如果我需要在實際代碼中切換到另一個數據庫客戶端實現,我只需要修改一行,而不是四處尋找對構造函數的引用。

當然,就像 Jon 的方法一樣,它不適用於您無法或不允許修改的 3rd 方代碼。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM