I have a method which implements different logic on data fetched from a DB depending on what the current date is.
I want to test it by having the unit test create objects, save them in the DB and invoke the tested method. However, in order to have predictable results I need to change the system date each time and I don't know how to do that in Java.
Suggestions?
You can generate your expected results using the current date.
Or you write your system to use a date/time you give it when being tested (rather than the clock) That way the time is always what the test expects.
I use something like
interface TimeSource {
long currentTimeMS(); // actually I have currentTimeNS
void currentTimeMS(long currentTimeMS);
}
enum VanillaTimeSource implements TimeSource {
INSTANCE;
@Override
public long currentTimeMS() {
return System.currentTimeMillis();
}
@Override
public void currentTimeMS(long currentTimeMS) {
// ignored
}
}
class FixedTimeSource implements TimeSource {
private long currentTimeMS;
@Override
public long currentTimeMS() {
return currentTimeMS;
}
@Override
public void currentTimeMS(long currentTimeMS) {
this.currentTimeMS = currentTimeMS;
}
}
In tests I use a FixedTimeSource which can be data driven e.g. set by inputs/events. In production I use a VanillaTimeSource.INSTANCE which ignores times in inputs/events and uses the current time.
You need to look at injecting something into your class that allows you to customize the way Time is presented.
For example
public interface TimeProvider {
DateTime getCurrentTime();
}
public class UnderTest {
// Inject this in some way (e.g. provide it in the constructor)
private TimeProvider timeProvider;
public void MyMethod() {
if (timeProvider.getCurrentTime() == "1234") {
// Do something
}
}
}
Now in your unit tests you can provide a fake implementation of time provider. In the real production code you can just return the current date time.
I had a similar problem recently with code I couldn't refactor too much (time constraints, didn't want to inadvertently break anything). It had a method I wanted to test which called System.currentTimeMillis() and the case I wanted to test would depend on what that value returned. Something like:
public class ClassINeedToTest {
public boolean doStuff() {
long l = System.currentTimeMillis();
// do some calculation based on l
// and return the calculation
}
}
To allow unit-testing, I refactored the class so it had a helper method which was protected
protected long getCurrentTimeMillis() {
// only for unit-testing purposes
return System.currentTimeMillis();
}
and this method was called by doStuff(). This didn't change the functionality but now meant that when I call it in the unit-test, I could then override this to return a specific value, like
ClassINeedToTest testClass = new ClassINeedToTest() {
protected long getCurrentTimeMillis() {
// return specific date for my test
return 12456778L;
}
};
boolean result = testClass.doStuff();
// test result with an assert here
This does however mean that I've polluted the interface of my class, so you may decide the cost is too high. There are probably better ways if you can refactor the code more.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With