在测试中使用DateTimeUtils.setCurrentMillisFixed是否安全? [英] Is it safe to use DateTimeUtils.setCurrentMillisFixed in tests?

查看:190
本文介绍了在测试中使用DateTimeUtils.setCurrentMillisFixed是否安全?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了测试与时间相关的代码,最好使用

In order to test time-dependent code it's good to use Virtual Clock Pattern

我们的想法是我们不使用new Date提取当前时间,而是从一个时钟中提取当前时间,该时钟可以通过虚拟时钟返回预定义的固定时间来进行模拟.

The idea is that we pull current time not using new Date, but from a clock which can be mocked with virtual clock returning predefined fixed time.

现在在Java中,我们有了带有DateTime类的JodaTime,它允许使用

Now in Java we have JodaTime with DateTime class and which allows to set sample time with

DateTimeUtils.setCurrentMillisFixed(today.getMillis());

并使用以下命令将固定时间重置为系统时间:

And reset the fixed time to a system time with:

DateTimeUtils.setCurrentMillisSystem();

这是好文章关于如何与TestNG一起使用.

Here is a good article on how to use it with TestNG.

现在是问题!

如果此技术在运行测试的时间范围内在全局上下文中全局设置固定时间,则将其与setUp和tearDown方法一起使用有多安全.只要我理解,它就不会起作用,只要我们没有在同一环境中并行运行此技术的两个并发测试.

How safe it's to use this technique with setUp and tearDown methods if it globally sets fixed time in global context for the time of running test. As long as I get it - it will only work as long as we don't have two concurrent tests with this technique running in the same environment in parallel.

推荐答案

您必须确保在tearDown方法中调用DateTimeUtils.setCurrentMillisSystem().这样一个测试不会影响另一个.即使测试中发生异常,TestNG也应调用tearDown.

You must ensure that DateTimeUtils.setCurrentMillisSystem() is invoked in the tearDown method. So that one test does not affect another. TestNG should invoke tearDown even if an exception occurs in your test.

当我想将类与System.currentTimeMillis();分离时,我通常更喜欢另一种方式.我介绍了这样的接口Clock和一个实现SystemClock:

I often prefer another way when I want to decouple a class from System.currentTimeMillis();. I introduce an interface Clock and one implementation SystemClock like this:

public interface Clock {
    public long getCurrentTimeMillis();
}

public class SystemClock implements Clock {
    public long getCurrentTimeMillis(){
        return System.currentTimeMillis();
    }
}

对于测试而言,创建一个简单的模拟很容易,该模拟要么在每次调用时返回固定时间,要么在一系列预定义时间返回.

For the tests it is then easy to create a mock that either returns a fixed time on every invocation or a series of predefined times.

有些人可能会争辩说引入这样的接口仅解耦一种方法是过度工程,这会对性能造成影响.但是幸运的是,我们有一个JIT编译器,并且由于JIT知道仅加载SystemClock类,因此它知道(目前)不存在其他实现.在这种假设下,它只能使用内联方法.

Some might argue that it is overengineering to introduce such an interface to decouple only one method and it would be a performance impact. But fortunately we have a JIT compiler and since JIT knows that only the SystemClock class is loaded it knows that no other implementation exist (at the moment). At this assumption it can just use inline method.

因此,我更喜欢以可以对其进行最佳测试的方式编写代码.

So I prefer to write code in the way it can be tested best.

编辑

对于Java 8,您可能希望使用

With Java 8 you might want to use the Supplier<Long> interface.

例如在您的客户端代码中,您可以使用方法引用

E.g. in your client code you can than use method references

public class SomeClass {
    private Supplier<Long> currentTimeMillisSupplier;

    public SomeClass(){
         this(System::currentTimeMillis);
    }

    SomeClass(Supplier<Long> currentTimeMillisSupplier){
        this.currentTimeMillisSupplier = currentTimeMillisSupplier;
    }
}

默认构造函数用于常规"使用,而其他包范围的构造函数可用于单元测试.只需将测试类放在同一包中即可.

The default constructor is for 'normal' use, while the other package scoped constructor can be used for unit tests. Just place the test class in the same package.

您还可以使用Clock界面,因为它是 @FunctionalInterface .

You can also use the Clock interface, because it is a @FunctionalInterface.

public class SomeClass {
    private Clock clock;

    public SomeClass(){
         this(System::currentTimeMillis);
    }

    public SomeClass(Clock clock){
        this.clock = clock;
    }
}

这篇关于在测试中使用DateTimeUtils.setCurrentMillisFixed是否安全?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆