简体   繁体   English

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

[英]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:具体来说:

  1. How can I mock the system clock (so I don't have to mock all the places where I call new DateTime() to get the current time)我怎样才能模拟系统时钟(这样我就不必模拟所有调用new DateTime()的地方来获取当前时间)
  2. How can I do the same for the default time zone?我怎样才能为默认时区做同样的事情?

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.

相关问题 在所有时区和带/不带 DST 的情况下进行带日期的单元测试 - Make unit tests with dates pass in all time zones and with/out DST 在Java中为所有时区保存日期时间 - Saving date time for all time zones in java Java日期DST调整我的日期/时间 - Java date DST adjusts my date / time 如何使我的代码找出在合理的时间内按下了哪个按钮? - How do I make my code find out which button was pressed within a reasonable amount of time? 单元测试有问题,我怎样才能让它只工作1次? - Problem with unit test, how can I make it works only 1 time? 如何为在运行时加载函数的应用程序编写测试? - How do I write tests for an application that loads functions at run time? 如何基于仅时间输入并考虑时区和DST来更改日期? - How to change a Date based on time-only input and account for time zone and DST? 如何使我的“ Date”对象在每次调用时都打印出不同的值? - How do I get my “Date” object to print out different values each time I call it? 如何对与Thread.interrupt一起使用的代码进行可重复的单元测试? - How to make repeatable unit tests of code that works with Thread.interrupt? 如何确保我将所有小数点后的所有数字从Excel导出到MySQL - How do I make sure I get all the digits past the decimal out of Excel and into MySQL
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM