覆盖 Java System.currentTimeMillis 以测试时间敏感代码

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2001671/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 02:20:31  来源:igfitidea点击:

Override Java System.currentTimeMillis for testing time sensitive code

javatestingjvmsystemtime

提问by Mike Clark

Is there a way, either in code or with JVM arguments, to override the current time, as presented via System.currentTimeMillis, other than manually changing the system clock on the host machine?

System.currentTimeMillis除了手动更改主机上的系统时钟之外,有没有办法在代码中或使用 JVM 参数覆盖当前时间,如通过 呈现的那样?

A little background:

一点背景:

We have a system that runs a number of accounting jobs that revolve much of their logic around the current date (ie 1st of the month, 1st of the year, etc)

我们有一个系统运行许多会计工作,这些工作围绕当前日期(即一个月的第一天,一年的第一天等)进行大部分逻辑

Unfortunately, a lot of the legacy code calls functions such as new Date()or Calendar.getInstance(), both of which eventually call down to System.currentTimeMillis.

不幸的是,许多遗留代码调用诸如new Date()或 之类的函数Calendar.getInstance(),这两者最终都会调用到System.currentTimeMillis.

For testing purposes, right now, we are stuck with manually updating the system clock to manipulate what time and date the code thinks that the test is being run.

现在,出于测试目的,我们不得不手动更新系统时钟来操纵代码认为测试正在运行的时间和日期。

So my question is:

所以我的问题是:

Is there a way to override what is returned by System.currentTimeMillis? For example, to tell the JVM to automatically add or subtract some offset before returning from that method?

有没有办法覆盖返回的内容System.currentTimeMillis?例如,告诉 JVM 在从该方法返回之前自动添加或减去一些偏移量?

Thanks in advance!

提前致谢!

采纳答案by Jon Skeet

I stronglyrecommend that instead of messing with the system clock, you bite the bullet and refactor that legacy code to use a replaceable clock. Ideallythat should be done with dependency injection, but even if you used a replaceable singleton you would gain testability.

强烈建议您不要弄乱系统时钟,而是硬着头皮重构遗留代码以使用可替换的时钟。理想情况下,这应该通过依赖注入来完成,但即使您使用可替换的单例,您也会获得可测试性。

This could almost be automated with search and replace for the singleton version:

这几乎可以通过搜索和替换单例版本实现自动化:

  • Replace Calendar.getInstance()with Clock.getInstance().getCalendarInstance().
  • Replace new Date()with Clock.getInstance().newDate()
  • Replace System.currentTimeMillis()with Clock.getInstance().currentTimeMillis()
  • 替换Calendar.getInstance()Clock.getInstance().getCalendarInstance()
  • 替换new Date()Clock.getInstance().newDate()
  • 替换System.currentTimeMillis()Clock.getInstance().currentTimeMillis()

(etc as required)

(等根据需要)

Once you've taken that first step, you can replace the singleton with DI a bit at a time.

一旦你迈出了第一步,你可以一次用 DI 替换单例。

回答by Jeremy Raymond

There really isn't a way to do this directly in the VM, but you could all something to programmatically set the system time on the test machine. Most (all?) OS have command line commands to do this.

确实没有办法直接在 VM 中执行此操作,但是您可以通过编程方式在测试机器上设置系统时间。大多数(全部?)操作系统都有命令行命令来执行此操作。

回答by Stephen

As said by Jon Skeet:

正如乔恩·斯基特所说

"use Joda Time" is almost always the best answer to any question involving "how do I achieve X with java.util.Date/Calendar?"

对于涉及“如何使用 java.util.Date/Calendar 实现 X”的任何问题,“使用 Joda 时间”几乎总是最佳答案。

So here goes (presuming you've just replaced all your new Date()with new DateTime().toDate())

所以这里去(假设你刚刚更换所有的new Date()new DateTime().toDate()

//Change to specific time
DateTimeUtils.setCurrentMillisFixed(millis);
//or set the clock to be a difference from system time
DateTimeUtils.setCurrentMillisOffset(millis);
//Reset to system time
DateTimeUtils.setCurrentMillisSystem();

If you want import a library that has an interface (see Jon's comment below), you could just use Prevayler's Clock, which will provide implementations as well as the standard interface. The full jar is only 96kB, so it shouldn't break the bank...

如果您想导入具有接口的库(请参阅下面的 Jon 评论),您可以只使用Prevayler's Clock,它将提供实现以及标准接口。完整的罐子只有 96kB,所以它不应该破坏银行......

回答by mhaller

Use Aspect-Oriented Programming (AOP, for example AspectJ) to weave the System class to return a predefined value which you could set within your test cases.

使用面向方面的编程(AOP,例如 AspectJ)来编织 System 类以返回您可以在测试用例中设置的预定义值。

Or weave the application classes to redirect the call to System.currentTimeMillis()or to new Date()to another utility class of your own.

或者编织应用程序类以将调用重定向到System.currentTimeMillis()或重定向到new Date()您自己的另一个实用程序类。

Weaving system classes (java.lang.*) is however a little bit more trickier and you might need to perform offline weaving for rt.jar and use a separate JDK/rt.jar for your tests.

java.lang.*然而,编织系统类 ( ) 有点棘手,您可能需要为 rt.jar 执行离线编织并使用单独的 JDK/rt.jar 进行测试。

It's called Binary weavingand there are also special toolsto perform weaving of System classes and circumvent some problems with that (e.g. bootstrapping the VM may not work)

它被称为二进制编织,还有一些特殊的工具来执行系统类的编织并规避一些问题(例如引导虚拟机可能不起作用)

回答by ReneS

Powermockworks great. Just used it to mock System.currentTimeMillis().

Powermock效果很好。只是用来嘲笑的System.currentTimeMillis()

回答by user1477398

In my opinion only a none-invasive solution can work. Especially if you have external libs and a big legacy code base there is no reliable way to mock out time.

在我看来,只有非侵入性的解决方案才能奏效。特别是如果您有外部库和大量遗留代码库,则没有可靠的方法来模拟时间。

JMockit ... works only for restricted number of times

JMockit ...仅适用于有限的次数

PowerMock & Co ...needs to mock the clientsto System.currentTimeMillis(). Again an invasive option.

PowerMock & Co ...需要将客户端模拟到 System.currentTimeMillis()。又是一个侵入性的选择。

From this I only see the mentioned javaagentor aopapproach being transparent to the whole system. Has anybody done that and could point to such a solution?

由此我只看到提到的javaagentaop方法对整个系统是透明的。有没有人这样做过并且可以指出这样的解决方案?

@jarnbjo: could you show some of the javaagent code please?

@jarnbjo:你能展示一些 javaagent 代码吗?

回答by virgo47

While using some DateFactory pattern seems nice, it does not cover libraries you can't control - imagine Validation annotation @Past with implementation relying on System.currentTimeMillis (there is such).

虽然使用一些 DateFactory 模式看起来不错,但它不包括您无法控制的库 - 想象验证注释 @Past 与依赖 System.currentTimeMillis 的实现(有这样的)。

That's why we use jmockit to mock the system time directly:

这就是为什么我们使用 jmockit 来直接模拟系统时间:

import mockit.Mock;
import mockit.MockClass;
...
@MockClass(realClass = System.class)
public static class SystemMock {
    /**
     * Fake current time millis returns value modified by required offset.
     *
     * @return fake "current" millis
     */
    @Mock
    public static long currentTimeMillis() {
        return INIT_MILLIS + offset + millisSinceClassInit();
    }
}

Mockit.setUpMock(SystemMock.class);

Because it's not possible to get to the original unmocked value of millis, we use nano timer instead - this is not related to wall clock, but relative time suffices here:

因为不可能达到millis的原始unmocked值,所以我们使用nano timer代替——这与挂钟无关,但相对时间在这里就足够了:

// runs before the mock is applied
private static final long INIT_MILLIS = System.currentTimeMillis();
private static final long INIT_NANOS = System.nanoTime();

private static long millisSinceClassInit() {
    return (System.nanoTime() - INIT_NANOS) / 1000000;
}

There is documented problem, that with HotSpot the time gets back to normal after a number of calls - here is the issue report: http://code.google.com/p/jmockit/issues/detail?id=43

有记录的问题,HotSpot 的时间在多次调用后恢复正常 - 这是问题报告:http: //code.google.com/p/jmockit/issues/detail?id=43

To overcome this we have to turn on one specific HotSpot optimization - run JVM with this argument -XX:-Inline.

为了克服这个问题,我们必须打开一个特定的 HotSpot 优化——用这个参数运行 JVM -XX:-Inline

While this may not be perfect for production, it is just fine for tests and it is absolutely transparent for application, especially when DataFactory doesn't make business sense and is introduced only because of tests. It would be nice to have built-in JVM option to run in different time, too bad it is not possible without hacks like this.

虽然这对于生产来说可能并不完美,但它对于测试来说很好,并且对于应用程序来说是绝对透明的,尤其是当 DataFactory 没有商业意义并且仅因为测试而引入时。有内置的 JVM 选项在不同的时间运行会很好,太糟糕了,没有这样的 hack 是不可能的。

Complete story is in my blog post here: http://virgo47.wordpress.com/2012/06/22/changing-system-time-in-java/

完整的故事在我的博客文章中:http: //virgo47.wordpress.com/2012/06/22/changed-system-time-in-java/

Complete handy class SystemTimeShifter is provided in the post. Class can be used in your tests, or it can be used as the first main class before your real main class very easily in order to run your application (or even whole appserver) in a different time. Of course, this is intented for testing purposes mainly, not for production environment.

帖子中提供了完整的便捷类 SystemTimeShifter。类可以在您的测试中使用,也可以非常轻松地用作真正的主类之前的第一个主类,以便在不同的时间运行您的应用程序(甚至整个应用程序服务器)。当然,这主要用于测试目的,而不是用于生产环境。

EDIT July 2014: JMockit changed a lot lately and you are bound to use JMockit 1.0 to use this correctly (IIRC). Definitely can't upgrade to newest version where interface is completly different. I was thinking about inlining just the necessary stuff, but as we don't need this thing in our new projects I'm not developing this thing at all.

编辑 2014 年 7 月:JMockit 最近发生了很大变化,您必须使用 JMockit 1.0 才能正确使用它(IIRC)。绝对不能升级到界面完全不同的最新版本。我正在考虑内联必要的东西,但由于我们在新项目中不需要这个东西,我根本没有开发这个东西。

回答by Basil Bourque

tl;dr

tl;博士

Is there a way, either in code or with JVM arguments, to override the current time, as presented via System.currentTimeMillis, other than manually changing the system clock on the host machine?

除了手动更改主机上的系统时钟之外,有没有办法在代码中或使用 JVM 参数覆盖当前时间,如通过 System.currentTimeMillis 呈现的那样?

Yes.

是的。

Instant.now( 
    Clock.fixed( 
        Instant.parse( "2016-01-23T12:34:56Z"), ZoneOffset.UTC
    )
)

ClockIn java.time

Clock在 java.time

We have a new solution to the problem of a pluggable clock replacement to facilitate testing with fauxdate-time values. The java.time packagein Java 8includes an abstract class java.time.Clock, with an explicit purpose:

我们为可插拔时钟替换问题提供了新的解决方案,以方便使用虚假日期时间值进行测试。该java.time包的Java 8包含一个抽象类java.time.Clock,有明确的目的:

to allow alternate clocks to be plugged in as and when required

允许在需要时插入备用时钟

You could plug in your own implementation of Clock, though you likely can find one already made to meet your needs. For your convenience, java.time includes static methods to yield special implementations. These alternate implementations can be valuable during testing.

您可以插入自己的 实现Clock,尽管您可能会找到一个已经满足您需求的实现。为方便起见,java.time 包含静态方法以产生特殊实现。这些替代实现在测试期间可能很有价值。

Altered cadence

改变节奏

The various tick…methods produce clocks that increment the current moment with a different cadence.

各种 tick…方法产生的时钟以不同的节奏递增当前时刻。

The default Clockreports a time updated as frequently as millisecondsin Java 8 and in Java 9 as fine as nanoseconds(depending on your hardware). You can ask for the true current moment to be reported with a different granularity.

默认情况下,Java 8 中的Clock更新频率为毫秒,Java 9 中的更新频率为纳秒(取决于您的硬件)。您可以要求以不同的粒度报告真实的当前时刻。

False clocks

假时钟

Some clocks can lie, producing a result different than that of the host OS' hardware clock.

一些时钟可能会撒谎,产生与主机操作系统硬件时钟不同的结果。

  • fixed- Reports a single unchanging (non-incrementing) moment as the current moment.
  • offset- Reports the current moment but shifted by the passed Durationargument.
  • fixed- 将单个不变(非递增)时刻报告为当前时刻。
  • offset- 报告当前时刻,但被传递的Duration参数移动。

For example, lock in the first moment of the earliest Christmas this year. in other words, when Santa and his reindeer make their first stop. The earliest time zone nowadays seems to be Pacific/Kiritimatiat +14:00.

例如,锁定今年最早的圣诞节的第一个时刻。换句话说,当圣诞老人和他的驯鹿第一站时。最早的时区现在似乎是Pacific/Kiritimati+14:00

LocalDate ld = LocalDate.now( ZoneId.of( "America/Montreal" ) );
LocalDate xmasThisYear = MonthDay.of( Month.DECEMBER , 25 ).atYear( ld.getYear() );
ZoneId earliestXmasZone = ZoneId.of( "Pacific/Kiritimati" ) ;
ZonedDateTime zdtEarliestXmasThisYear = xmasThisYear.atStartOfDay( earliestXmasZone );
Instant instantEarliestXmasThisYear = zdtEarliestXmasThisYear.toInstant();
Clock clockEarliestXmasThisYear = Clock.fixed( instantEarliestXmasThisYear , earliestXmasZone );

Use that special fixed clock to always return the same moment. We get the first moment of Christmas day in Kiritimati, with UTC showing a wall-clock timeof fourteen hours earlier, 10 AM on the prior date of the 24th of December.

使用那个特殊的固定时钟总是返回相同的时刻。我们在Kiritimati看到圣诞节的第一个时刻,UTC 显示的挂钟时间提前了 14 小时,即 12 月 24 日的前一天上午 10 点。

Instant instant = Instant.now( clockEarliestXmasThisYear );
ZonedDateTime zdt = ZonedDateTime.now( clockEarliestXmasThisYear );

instant.toString(): 2016-12-24T10:00:00Z

zdt.toString(): 2016-12-25T00:00+14:00[Pacific/Kiritimati]

Instant.toString(): 2016-12-24T10:00:00Z

zdt.toString(): 2016-12-25T00:00+14:00[Pacific/Kiritimati]

See live code in IdeOne.com.

在 IdeOne.com 中查看实时代码

True time, different time zone

真实时间,不同时区

You can control which time zone is assigned by the Clockimplementation. This might be useful in some testing. But I do not recommend this in production code, where you should always specify explicitly the optional ZoneIdor ZoneOffsetarguments.

您可以控制Clock实现分配的时区。这在某些测试中可能很有用。但是我不建议在生产代码中使用它,您应该始终明确指定可选ZoneIdZoneOffset参数。

You can specify that UTC be the default zone.

您可以将 UTC 指定为默认区域。

ZonedDateTime zdtClockSystemUTC = ZonedDateTime.now ( Clock.systemUTC () );

You can specify any particular time zone. Specify a proper time zone namein the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as ESTor ISTas they are nottrue time zones, not standardized, and not even unique(!).

您可以指定任何特定的时区。以、、 或等格式指定正确的时区名称。永远不要使用 3-4 个字母的缩写,例如或因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。continent/regionAmerica/MontrealAfrica/CasablancaPacific/AucklandESTIST

ZonedDateTime zdtClockSystem = ZonedDateTime.now ( Clock.system ( ZoneId.of ( "America/Montreal" ) ) );

You can specify the JVM's current default time zone should be the default for a particular Clockobject.

您可以指定 JVM 的当前默认时区应该是特定Clock对象的默认时区。

ZonedDateTime zdtClockSystemDefaultZone = ZonedDateTime.now ( Clock.systemDefaultZone () );

Run this code to compare. Note that they all report the same moment, the same point on the timeline. They differ only in wall-clock time; in other words, three ways to say the same thing, three ways to display the same moment.

运行此代码进行比较。请注意,它们都报告同一时刻,时间轴上的同一点。它们仅在挂钟时间上有所不同;换句话说,说同样的事情的三种方式,展示同一时刻的三种方式。

System.out.println ( "zdtClockSystemUTC.toString(): " + zdtClockSystemUTC );
System.out.println ( "zdtClockSystem.toString(): " + zdtClockSystem );
System.out.println ( "zdtClockSystemDefaultZone.toString(): " + zdtClockSystemDefaultZone );

America/Los_Angeleswas the JVM current default zone on the computer that ran this code.

America/Los_Angeles是运行此代码的计算机上的 JVM 当前默认区域。

zdtClockSystemUTC.toString(): 2016-12-31T20:52:39.688Z

zdtClockSystem.toString(): 2016-12-31T15:52:39.750-05:00[America/Montreal]

zdtClockSystemDefaultZone.toString(): 2016-12-31T12:52:39.762-08:00[America/Los_Angeles]

zdtClockSystemUTC.toString(): 2016-12-31T20:52:39.688Z

zdtClockSystem.toString(): 2016-12-31T15:52:39.750-05:00[美国/蒙特利尔]

zdtClockSystemDefaultZone.toString(): 2016-12-31T12:52:39.762-08:00[America/Los_Angeles]

The Instantclass is always in UTC by definition. So these three zone-related Clockusages have exactly the same effect.

根据Instant定义,该类始终采用 UTC。所以这三个与区域相关的Clock用法具有完全相同的效果。

Instant instantClockSystemUTC = Instant.now ( Clock.systemUTC () );
Instant instantClockSystem = Instant.now ( Clock.system ( ZoneId.of ( "America/Montreal" ) ) );
Instant instantClockSystemDefaultZone = Instant.now ( Clock.systemDefaultZone () );

instantClockSystemUTC.toString(): 2016-12-31T20:52:39.763Z

instantClockSystem.toString(): 2016-12-31T20:52:39.763Z

instantClockSystemDefaultZone.toString(): 2016-12-31T20:52:39.763Z

InstantClockSystemUTC.toString(): 2016-12-31T20:52:39.763Z

InstantClockSystem.toString(): 2016-12-31T20:52:39.763Z

InstantClockSystemDefaultZone.toString(): 2016-12-31T20:52:39.763Z

Default clock

默认时钟

The implementation used by default for Instant.nowis the one returned by Clock.systemUTC(). This is the implementation used when you do not specify a Clock. See for yourself in pre-release Java 9 source code for Instant.now.

for 默认使用的实现Instant.now是由 返回的实现Clock.systemUTC()。这是未指定Clock. 在预发布的 Java 9 源代码中Instant.now亲自查看.

public static Instant now() {
    return Clock.systemUTC().instant();
}

The default Clockfor OffsetDateTime.nowand ZonedDateTime.nowis Clock.systemDefaultZone(). See source code.

默认ClockOffsetDateTime.nowZonedDateTime.nowClock.systemDefaultZone()。请参阅源代码

public static ZonedDateTime now() {
    return now(Clock.systemDefaultZone());
}

The behavior of the default implementations changed between Java 8 and Java 9. In Java 8, the current moment is captured with a resolution only in millisecondsdespite the classes' ability to store a resolution of nanoseconds. Java 9 brings a new implementation able to capture the current moment with a resolution of nanoseconds – depending, of course, on the capability of your computer hardware clock.

默认实现的行为在 Java 8 和 Java 9 之间发生了变化。在 Java 8 中,尽管类能够存储nanoseconds分辨率,但捕获当前时刻的分辨率仅为毫秒。Java 9 带来了一种新的实现,能够以纳秒的分辨率捕捉当前时刻——当然,这取决于计算机硬件时钟的能力。



About java.time

关于java.time

The java.timeframework is built into Java 8 and later. These classes supplant the troublesome old legacydate-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date, Calendar, & SimpleDateFormat

The Joda-Timeproject, now in maintenance mode, advises migration to the java.timeclasses.

现在处于维护模式Joda-Time项目建议迁移到java.time类。

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是JSR 310

You may exchange java.timeobjects directly with your database. Use a JDBC drivercompliant with JDBC 4.2or later. No need for strings, no need for java.sql.*classes.

您可以直接与您的数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC 驱动程序。不需要字符串,不需要类。java.sql.*

Where to obtain the java.time classes?

从哪里获得 java.time 类?

The ThreeTen-Extraproject extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

ThreeTen-额外项目与其他类扩展java.time。该项目是未来可能添加到 java.time 的试验场。你可能在这里找到一些有用的类,比如IntervalYearWeekYearQuarter,和更多

回答by Paresh Mayani

If you want to mock the method having System.currentTimeMillis()argument then you can pass anyLong()of Matchers class as an argument.

如果要模拟具有System.currentTimeMillis()参数的方法,则可以将anyLong()Matchers 类作为参数传递。

P.S. I am able to run my test case successfully using the above trick and just to share more details about my test that I am using PowerMock and Mockito frameworks.

PS 我能够使用上述技巧成功运行我的测试用例,只是为了分享有关我使用 PowerMock 和 Mockito 框架的测试的更多详细信息。

回答by KiriSakow

A working way to override current system time for JUnit testing purposes in a Java 8 web application with EasyMock, without Joda Time, and without PowerMock.

在 Java 8 Web 应用程序中使用 EasyMock、没有 Joda Time 和没有 PowerMock 覆盖当前系统时间以进行 JUnit 测试。

Here's what you need to do:

您需要执行以下操作:

What needs to be done in the tested class

测试类需要做什么

Step 1

第1步

Add a new java.time.Clockattribute to the tested class MyServiceand make sure the new attribute will be initialized properly at default values with an instantiation block or a constructor:

java.time.Clock向测试类添加一个新属性,MyService并确保使用实例化块或构造函数在默认值下正确初始化新属性:

import java.time.Clock;
import java.time.LocalDateTime;

public class MyService {
  // (...)
  private Clock clock;
  public Clock getClock() { return clock; }
  public void setClock(Clock newClock) { clock = newClock; }

  public void initDefaultClock() {
    setClock(
      Clock.system(
        Clock.systemDefaultZone().getZone() 
        // You can just as well use
        // java.util.TimeZone.getDefault().toZoneId() instead
      )
    );
  }
  { 
    initDefaultClock(); // initialisation in an instantiation block, but 
                        // it can be done in a constructor just as well
  }
  // (...)
}

Step 2

第2步

Inject the new attribute clockinto the method which calls for a current date-time. For instance, in my case I had to perform a check of whether a date stored in dataase happened before LocalDateTime.now(), which I remplaced with LocalDateTime.now(clock), like so:

将新属性clock注入到调用当前日期时间的方法中。例如,在我的情况下,我必须检查存储在 dataase 中的日期是否发生在 之前LocalDateTime.now(),我将其替换为LocalDateTime.now(clock),如下所示:

import java.time.Clock;
import java.time.LocalDateTime;

public class MyService {
  // (...)
  protected void doExecute() {
    LocalDateTime dateToBeCompared = someLogic.whichReturns().aDate().fromDB();
    while (dateToBeCompared.isBefore(LocalDateTime.now(clock))) {
      someOtherLogic();
    }
  }
  // (...) 
}

What needs to be done in the test class

测试类需要做什么

Step 3

第 3 步

In the test class, create a mock clock object and inject it into the tested class's instance just before you call the tested method doExecute(), then reset it back right afterwards, like so:

在测试类中,创建一个模拟时钟对象,并在调用测试方法之前将其注入到测试类的实例中doExecute(),然后立即将其重置,如下所示:

import java.time.Clock;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import org.junit.Test;

public class MyServiceTest {
  // (...)
  private int year = 2017;
  private int month = 2;
  private int day = 3;

  @Test
  public void doExecuteTest() throws Exception {
    // (...) EasyMock stuff like mock(..), expect(..), replay(..) and whatnot

    MyService myService = new MyService();
    Clock mockClock =
      Clock.fixed(
        LocalDateTime.of(year, month, day, 0, 0).toInstant(OffsetDateTime.now().getOffset()),
        Clock.systemDefaultZone().getZone() // or java.util.TimeZone.getDefault().toZoneId()
      );
    myService.setClock(mockClock); // set it before calling the tested method

    myService.doExecute(); // calling tested method 

    myService.initDefaultClock(); // reset the clock to default right afterwards with our own previously created method

    // (...) remaining EasyMock stuff: verify(..) and assertEquals(..)
    }
  }

Check it in debug mode and you will see the date of 2017 Feb 3 has been correctly injected into myServiceinstance and used in the comparison instruction, and then has been properly reset to current date with initDefaultClock().

在调试模式下检查,您将看到 2017 年 2 月 3 日的日期已正确注入myService实例并在比较指令中使用,然后已正确重置为当前日期initDefaultClock()