How to override / control how the JVM gets the system date?

How do you machete / trick the JVM to get a date other than the current system date? I have a set of tests in JUnit that I don’t want to change, but instead I want to change the parameter so that when the JVM retrieves the date, it returns the date I need.

Have you done something like this before?

Thanks.

+4
source share
4 answers

There are several ways to do this:

  • if you can rewrite the code - as mentioned in some other answers, basically you need a custom NowProvider, DateFactory or other strategy (I like to inject NowProvider.now () as a dropin replacement for System.currentTimeMillis)

  • Powermock and some other tools allow you to use ClassLoader tricks to override static methods, even system methods

+5
source

You can have a DateFactory interface with two implementations that always returns new Date() (this will be used during production) and a mock object that returns Date objects that are more suitable for your unit tests.

(It is suggested that you can modify your code to make it more suitable for unit testing.)

+1
source

I would rather try to hide this functionality behind a mocked interface, so that the "real" implementation will get the system date, and your mock implementation will return any date that you configured.

Passing the system date in unit tests is not a very nice thing for me - I will try to avoid it if I can. Unit tests should be as context sensitive as possible - this saves a ton of problems in the long run.

However, if you cannot change the code you are testing, you may not have another way. Then the question arises: are you only interested in the date or the full timestamp? The latter case sounds completely hopeless to me (in any other way than the aforementioned interface layout), since I think that just resetting the date before running your tests is not enough - you need a fixed point in time that will be returned throughout your unit tests. Perhaps your tests will go fast enough to finish until the clock starts ticking, maybe not - maybe they pass right now, and then begin to happen by chance some time after adding the following test: - (

If you only need a date, you can try changing the date in the @BeforeClass method and then reset it to @AfterClass , although this is rude.

+1
source

You can write a TestRule for it. Maybe something like this:

 import org.joda.time.DateTime; import org.joda.time.DateTimeUtils; import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; public class FixedDateTimeRule implements TestRule { private final DateTime fixedDate; public FixedDateTimeRule(DateTime fixedDate) { this.fixedDate = fixedDate; } /* * (non-Javadoc) * * @see org.junit.rules.TestRule#apply(org.junit.runners.model.Statement, org.junit.runner.Description) */ @Override public Statement apply(final Statement base, Description description) { return new Statement() { @Override public void evaluate() throws Throwable { DateTimeUtils.setCurrentMillisFixed(fixedDate.getMillis()); try { base.evaluate(); } finally { DateTimeUtils.setCurrentMillisSystem(); } } }; } } @Rule public FixedDateTimeRule fixedDateTime = new FixedDateTimeRule(new DateTime(...)) @Test public void someKindOfTestThatNeedsAFixedDateTime() { ... } 
0
source

Source: https://habr.com/ru/post/1305608/


All Articles