繁体   English   中英

如何编写单元测试以确保我的基于日期/时间的代码适用于所有时区以及有/无夏令时?

[英]How do I write unit tests to make sure my date/time based code works for all time zones and with/out DST?

我正在使用 JodaTime 2.1,我正在寻找一种模式来对执行日期/时间操作的代码进行单元测试,以确保它在所有时区都表现良好并且独立于DST

具体来说:

  1. 我怎样才能模拟系统时钟(这样我就不必模拟所有调用new DateTime()的地方来获取当前时间)
  2. 我怎样才能为默认时区做同样的事情?

您可以使用@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();

    ....
}

这将在执行SomeTest每个测试之前将当前时区更改为UTC,并在每次测试后恢复默认时区。

如果要检查多个时区,请使用如下规则:

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 );
}

这将使用UTC执行AbstractTZTest所有测试。 对于您要测试的每个时区,您将需要另一个类:

public class UTCTest extends AbstractTZTest {
    @Rule public TZRule tzRule = new TZRule( DateTimeZone.forID( "..." );
}

由于测试用例是继承的,所以 - 只需要定义规则。

以类似的方式,您可以移动系统时钟。 使用调用DateTimeUtils.setCurrentMillisProvider(...)的规则来模拟测试在特定时间运行,并使用DateTimeUtils.setCurrentMillisSystem()来恢复默认值。

注意:您的提供商需要一种方法来使时钟滴答或所有新的DateTime实例将具有相同的值。 每次调用getMillis()时,我经常将值提前一毫秒。

注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()
{
//...
}

您还可以使用 JUnit Pioneer: https ://junit-pioneer.org/docs/default-locale-timezone/

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM