私は JodaTime 2.1 を使用しており、日付/時刻操作を実行して、すべてのタイムゾーンでDSTとは無関係に適切に動作することを確認するコードを単体テストするパターンを探しています。
具体的には:
new DateTime()
システムクロックをモックするにはどうすればよいですか (そのため、現在の時刻を取得するために呼び出すすべての場所をモックする必要はありません)- デフォルトのタイムゾーンで同じことを行うにはどうすればよいですか?
これには a@Rule
を使用できます。ルールのコードは次のとおりです。
import org.joda.time.DateTimeZone;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
public class UTCRule extends TestWatcher {
private DateTimeZone origDefault = DateTimeZone.getDefault();
@Override
protected void starting( Description description ) {
DateTimeZone.setDefault( DateTimeZone.UTC );
}
@Override
protected void finished( Description description ) {
DateTimeZone.setDefault( origDefault );
}
}
次のようにルールを使用できます。
public class SomeTest {
@Rule
public UTCRule utcRule = new UTCRule();
....
}
これにより、各テストが実行される前に現在のタイム ゾーンが UTC に変更SomeTest
され、各テストの後にデフォルトのタイム ゾーンが復元されます。
複数のタイム ゾーンを確認する場合は、次のようなルールを使用します。
import org.joda.time.DateTimeZone;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
public class TZRule extends TestWatcher {
private DateTimeZone origDefault = DateTimeZone.getDefault();
private DateTimeZone tz;
public TZRule( DateTimeZone tz ) {
this.tz = tz;
}
@Override
protected void starting( Description description ) {
DateTimeZone.setDefault( tz );
}
@Override
protected void finished( Description description ) {
DateTimeZone.setDefault( origDefault );
}
}
影響を受けるすべてのテストを抽象基本クラスに入れAbstractTZTest
て拡張します。
public class UTCTest extends AbstractTZTest {
@Rule public TZRule tzRule = new TZRule( DateTimeZone.UTC );
}
これにより、すべてのテストがAbstractTZTest
UTC で実行されます。テストするタイム ゾーンごとに、別のクラスが必要になります。
public class UTCTest extends AbstractTZTest {
@Rule public TZRule tzRule = new TZRule( DateTimeZone.forID( "..." );
}
テストケースは継承されるので、あとはルールを定義するだけです。
同様の方法で、システム クロックをシフトできます。DateTimeUtils.setCurrentMillisProvider(...)
テストが特定の時間に実行されることをシミュレートしDateTimeUtils.setCurrentMillisSystem()
、デフォルトを復元するために呼び出すルールを使用します。
注: プロバイダーには、クロックを刻む方法が必要です。そうしないと、すべての新しいDateTime
インスタンスが同じ値になります。getMillis()
が呼び出されるたびに、値を 1 ミリ秒ずつ進めることがよくあります。
注 2: これは joda-time でのみ機能します。には影響しませんnew java.util.Date()
。
注 3: これらのテストを並行して実行することはできなくなりました。それらは順番に実行する必要があります。そうしないと、別のテストの実行中にいずれかがデフォルトのタイムゾーンを復元する可能性が高くなります。
for (String zoneId : DateTimeZone.getAvailableIDs())
{
DateTime testedDate1;
DateTime testedDate2;
try
{
final DateTimeZone tz = DateTimeZone.forID(zoneId);
// your test with testedDate1 and testedDate2
}
catch (final IllegalArgumentException e)
{
// catching DST problem
testedDate1 = testetDate1.plusHours(1);
testedDate2 = testetDate2.plusHours(1);
// repeat your test for this dates
}
}
シングルテストに変更
DateTimeZone default;
DateTimeZone testedTZ;
@Before
public void setUp()
{
default = GateTimeZone.getDefault();
DateTimeZone.setDefault
}
@After
public void tearDown()
{
default = GateTimeZone.setDefault();
DateTimeZone.setDefault(testedTZ)
}
@Test
public void test()
{
//...
}