[英]How do I write unit tests to make sure my date/time based code works for all time zones and with/out DST?
I'm using JodaTime 2.1 and I'm looking for a pattern to unit test code which performs date/time operations to make sure it behaves well for all time zones and independent of DST .我正在使用 JodaTime 2.1,我正在寻找一种模式来对执行日期/时间操作的代码进行单元测试,以确保它在所有时区都表现良好并且独立于DST 。
Specifically:具体来说:
new DateTime()
to get the current time)我怎样才能模拟系统时钟(这样我就不必模拟所有调用new DateTime()
的地方来获取当前时间) You can use a @Rule
for this. 您可以使用@Rule
。 Here is the code for the 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 );
}
}
You can use the rule like this: 你可以使用这样的规则:
public class SomeTest {
@Rule
public UTCRule utcRule = new UTCRule();
....
}
This will change the current time zone to UTC before each test in SomeTest
will be executed and it will restore the default time zone after each test. 这将在执行SomeTest
每个测试之前将当前时区更改为UTC,并在每次测试后恢复默认时区。
If you want to check several time zones, use a rule like this one: 如果要检查多个时区,请使用如下规则:
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 );
}
}
Put all the affected tests in an abstract base class AbstractTZTest
and extend it: 将所有受影响的测试放在抽象基类AbstractTZTest
并对其进行扩展:
public class UTCTest extends AbstractTZTest {
@Rule public TZRule tzRule = new TZRule( DateTimeZone.UTC );
}
That will execute all tests in AbstractTZTest
with UTC. 这将使用UTC执行AbstractTZTest
所有测试。 For each time zone that you want to test, you'll need another class: 对于您要测试的每个时区,您将需要另一个类:
public class UTCTest extends AbstractTZTest {
@Rule public TZRule tzRule = new TZRule( DateTimeZone.forID( "..." );
}
Since test cases are inherited, that's all - you just need to define the rule. 由于测试用例是继承的,所以 - 只需要定义规则。
In a similar way, you can shift the system clock. 以类似的方式,您可以移动系统时钟。 Use a rule that calls DateTimeUtils.setCurrentMillisProvider(...)
to simulate that the test runs at a certain time and DateTimeUtils.setCurrentMillisSystem()
to restore the defaults. 使用调用DateTimeUtils.setCurrentMillisProvider(...)
的规则来模拟测试在特定时间运行,并使用DateTimeUtils.setCurrentMillisSystem()
来恢复默认值。
Note: Your provider will need a way to make the clock tick or all new DateTime
instances will have the same value. 注意:您的提供商需要一种方法来使时钟滴答或所有新的DateTime
实例将具有相同的值。 I often advance the value by a millisecond each time getMillis()
is called. 每次调用getMillis()
时,我经常将值提前一毫秒。
Note 2: That only works with joda-time. 注2:这只适用于joda-time。 It doesn't affect new java.util.Date()
. 它不会影响new java.util.Date()
。
Note 3: You can't run these tests in parallel anymore. 注3:您不能再并行运行这些测试。 They must run in sequence or one of them will most likely restore the default timezone while another test is running. 它们必须按顺序运行,否则其中一个很可能会在另一个测试运行时恢复默认时区。
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
}
}
Change for single test 改变单一测试
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()
{
//...
}
You can also use JUnit Pioneer: https://junit-pioneer.org/docs/default-locale-timezone/您还可以使用 JUnit Pioneer: https ://junit-pioneer.org/docs/default-locale-timezone/
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.