I am doing test cases and I don't now how to test this function. Could you give me some ideas? I was trying to use Mockito but I keep getting get null. I would appreciate your help.
This is the function I want to test.
public static Date optDate(JSONObject json, String key) {
if(!json.isNull(key)) {
try {
DateTime dt = JSONUtils.dateFormatter.withZoneUTC().parseDateTime(json.optString(key));
Date date = dt.toDate();
return date;
} catch(Exception e) {
}
}
return null;
}
And I am testing it in this way.
#RunWith(MockitoJUnitRunner.class)
public class JSONUtilsTest {
static String dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
static DateTimeFormatter dateFormatter = DateTimeFormat.forPattern(dateFormat);
DateTime dt = JSONUtilsTest.dateFormatter.withZoneUTC().parseDateTime("2011-11-02T02:50:12.208Z");
Date date = dt.toDate();
#Mock
JSONObject JSONMock = Mockito.mock(JSONObject.class);
JSONUtils mJSONUtils = Mockito.mock(JSONUtils.class);
#Before
public void setup() {
doReturn(date).when(mJSONUtils).optDate(JSONMock,"possessionDate");
}
#Test
public void optDateShouldReturnValueOnValidString() {
Date result = JSONUtils.optDate(JSONMock, "possessionDate");
Assert.assertEquals("2011-11-02",result);
}
}
*****************************EDIT 1 ***********************************************
After trying to find a correct way to test this method. I did this.
#RunWith(MockitoJUnitRunner.class)
public class JSONUtilsTest {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
Date today = new Date();
String todayString = dateFormat.format(today);
#Mock
JSONObject JSONMock = Mockito.mock(JSONObject.class);
#Before
public void setup() {
when(JSONUtils.optString(JSONMock, "possessionDate")).thenReturn(todayString);
}
#Test
public void optDateShouldReturnValueOnValidString() {
Date result = JSONUtils.optDate(JSONMock, "possessionDate");
Assert.assertEquals(today,result);
}
Mock based testing always works like this:
You create some sort of mock object of a certain class
You "instruct" the mock for the expected calls and specify potential return values
You trigger your "code under test"; using that mock object as "input" to your code under test
You check that your "code under test" creates the expected outputs; depending on your mocking framework, you verify that your mock object saw the specified calls.
Related
I have the following class that includes a list of Date which I want to mashall. I have created the JaxBAdapter for the Date class, but it seems it is not called.
I think the problem is the fact that I'm using a list and not just a Date variable.
Could you give me some hint on how should I code the adapter or annotate the class so each element of the list is mashalled using the adapter?
Will it work for JSON serialization as well? I'm planning to use this classes on my REST webservice.
Root.java
#XmlRootElement(name = "root")
#XmlAccessorType(XmlAccessType.FIELD)
public class Root {
#XmlElementWrapper(name="timePeriods")
#XmlElement(name = "timePeriod")
#JsonProperty(value = "timePeriod")
#XmlJavaTypeAdapter(value = JaxBDateThreadSafeAdapter.class, type = Date.class)
private List<Date> timePeriod;
public Root() {
this(new ArrayList<String>(), new ArrayList<Date>(2));
}
public Root(List<Date> timePeriod) {
this.timePeriod = new ArrayList<Date>(timePeriod);
}
}
JaxBAdapter
public class JaxBDateThreadSafeAdapter extends XmlAdapter<String, Date> {
/**
* Thread safe {#link DateFormat}.
*/
private static final ThreadLocal<DateFormat> DATE_FORMAT_TL =
new ThreadLocal<DateFormat>() {
#Override
protected DateFormat initialValue() {
// return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// ISO 8601 format
return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
}
};
#Override
public String marshal(Date v) throws Exception {
return DATE_FORMAT_TL.get().format(v);
}
#Override
public Date unmarshal(String v) throws Exception {
return DATE_FORMAT_TL.get().parse(v);
}
}
The #XmlJavaTypeAdapter works as such with java.util.List as well. But the problem in the adapter class is the date format that is used. JAXB (atleast 2.x onwards) is not strict and dont report such errors and quietly suppresses it.
return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
change to
return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
I'm trying to test a class that calculates age. The method that calculates the age looks like this:
public static int getAge(LocalDate birthdate) {
LocalDate today = new LocalDate();
Period period = new Period(birthdate, today, PeriodType.yearMonthDay());
return period.getYears();
}
Since I want the JUnit to be time-independent I want the today variable to always be January 1, 2016. To do this I tried going the Mockito.when route but am running into trouble.
I first had this:
public class CalculatorTest {
#Before
public void setUp() throws Exception {
LocalDate today = new LocalDate(2016,1,1);
Mockito.when(new LocalDate()).thenReturn(today);
}
}
But to that I got this error:
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.
Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.
So then I tried to make a method inside the Calculator class to return the current date like so:
public static LocalDate getCurrentDate() {
return new LocalDate();
}
public static int getAge(LocalDate birthdate) {
LocalDate today = getCurrentDate();
Period period = new Period(birthdate, today, PeriodType.yearMonthDay());
return period.getYears();
}
So that I could do this:
public class CalculatorTest {
#Before
public void setUp() throws Exception {
CalculatorTest mock = Mockito.mock(CalculatorTest.class);
LocalDate today = new LocalDate(2016,1,1);
Mockito.when(mock.getCurrentDate()).thenReturn(today);
}
}
But to that I get the exact same problem. So any ideas on how to return a predefined localdate object whenever the age calculation is triggered?
Instead of mocking, I'd suggest using Joda's DateTimeUtils to "freeze" the time. You would also need to use org.joda.time.LocalDate instead of java.time.LocalDate in your application code.
public class CalculatorTest {
#Before
public void setUp() throws Exception {
DateTimeUtils.setCurrentMillisFixed(new LocalDate(2016,1,1).toDateTimeAtStartOfDay().getMillis());
}
#After
public void tearDown() {
DateTimeUtils.setCurrentMillisSystem();
}
}
For pure Java, consider some approaches described here, particularly, injecting a Clock or using PowerMock.
Injecting a Clock is quite similar to the Joda example; you just need to maintain your own static Clock. Your application code would look like this:
static Clock appClock = Clock.systemDefaultZone();
public static int getAge(LocalDate birthdate) {
LocalDate today = LocalDate.now(appClock);
Period period = new Period(birthdate, today, PeriodType.yearMonthDay());
return period.getYears();
}
And the test would freeze the time like this:
public class CalculatorTest {
#Before
public void setUp() {
appClock = Clock.fixed(LocalDate(2016,1,1).toDateTimeAtStartOfDay(), ZoneId.systemDefault());
}
#After
public void tearDown() {
appClock = Clock.systemDefaultZone();
}
}
I suggest you to trick to test your method:
public static int getAge(LocalDate currDate, LocalDate birthdate) {
Period period = new Period(birthdate, currDate, PeriodType.yearMonthDay());
return period.getYears();
}
public static int getAge(LocalDate birthdate) {
return getAge(new LocalDate (), birthdate);
}
I allways use my own TimeFactory to retrieve the currentdate in my application. This way I am flexible on manipulating it (during JUnit testing). This is what the TimeFactory looks like:
public final class TimeFactory {
static int offsetAmount = 0;
static TemporalUnit offsetUnit = ChronoUnit.MILLIS;
public static LocalDateTime getLocalDateTimeNow() {
return LocalDateTime.now().plus(offsetAmount, offsetUnit);
}
public static void reset() {
offsetAmount = 0;
}
public static void travelToPast(int amount, TemporalUnit unit) {
offsetAmount = amount * -1;
offsetUnit = unit;
}
public static void travelToFuture(int amount, TemporalUnit unit) {
offsetAmount = amount;
offsetUnit = unit;
}
}
Using this TimeFactory I can easily do Time travelling:
// start test
TimeFactory.travelToPast(10, ChronoUnit.HOURS);
// continue tests
TimeFactory.reset();
// check that things have happend in the past.
You can expand this code to fix the time.
Joda Time has a nice DateTimeUtils.setCurrentMillisFixed() to mock time.
It's very practical in tests.
Is there an equivalent in Java 8's java.time API?
The closest thing is the Clock object. You can create a Clock object using any time you want (or from the System current time). All date.time objects have overloaded now methods that take a clock object instead for the current time. So you can use dependency injection to inject a Clock with a specific time:
public class MyBean {
private Clock clock; // dependency inject
...
public void process(LocalDate eventDate) {
if (eventDate.isBefore(LocalDate.now(clock)) {
...
}
}
}
See Clock JavaDoc for more details
I used a new class to hide the Clock.fixed creation and simplify the tests:
public class TimeMachine {
private static Clock clock = Clock.systemDefaultZone();
private static ZoneId zoneId = ZoneId.systemDefault();
public static LocalDateTime now() {
return LocalDateTime.now(getClock());
}
public static void useFixedClockAt(LocalDateTime date){
clock = Clock.fixed(date.atZone(zoneId).toInstant(), zoneId);
}
public static void useSystemDefaultZoneClock(){
clock = Clock.systemDefaultZone();
}
private static Clock getClock() {
return clock ;
}
}
public class MyClass {
public void doSomethingWithTime() {
LocalDateTime now = TimeMachine.now();
...
}
}
#Test
public void test() {
LocalDateTime twoWeeksAgo = LocalDateTime.now().minusWeeks(2);
MyClass myClass = new MyClass();
TimeMachine.useFixedClockAt(twoWeeksAgo);
myClass.doSomethingWithTime();
TimeMachine.useSystemDefaultZoneClock();
myClass.doSomethingWithTime();
...
}
I used a field
private Clock clock;
and then
LocalDate.now(clock);
in my production code. Then I used Mockito in my unit tests to mock the Clock using Clock.fixed():
#Mock
private Clock clock;
private Clock fixedClock;
Mocking:
fixedClock = Clock.fixed(Instant.now(), ZoneId.systemDefault());
doReturn(fixedClock.instant()).when(clock).instant();
doReturn(fixedClock.getZone()).when(clock).getZone();
Assertion:
assertThat(expectedLocalDateTime, is(LocalDate.now(fixedClock)));
I find using Clock clutters your production code.
You can use JMockit or PowerMock to mock static method invocations in your test code.
Example with JMockit:
#Test
public void testSth() {
LocalDate today = LocalDate.of(2000, 6, 1);
new Expectations(LocalDate.class) {{
LocalDate.now(); result = today;
}};
Assert.assertEquals(LocalDate.now(), today);
}
EDIT: After reading the comments on Jon Skeet's answer to a similar question here on SO I disagree with my past self. More than anything else the argument convinced me that you cannot parallize tests when you mock static methods.
You can/must still use static mocking if you have to deal with legacy code, though.
A bit late, but here it is what I use to mock time using the java.date API in Kotlin:
val now = LocalDate.of(2021, Month.FEBRUARY, 19)
val clock = Clock.fixed(Instant.ofEpochSecond(
now.atStartOfDay().toEpochSecond(ZoneOffset.UTC)
), ZoneId.systemDefault())
and then you can pass your clock to the class to test
val classToTest = MyClass(clock)
Of course, inside your testable class you will use the clock to retrieve dates or times:
class MyClass(private val clock: Clock = Clock.systemDefaultZone()) {
// ...
fun doSomething() = LocalDate.now(clock)...
I need LocalDate instance instead of LocalDateTime.
With such reason I created following utility class:
public final class Clock {
private static long time;
private Clock() {
}
public static void setCurrentDate(LocalDate date) {
Clock.time = date.toEpochDay();
}
public static LocalDate getCurrentDate() {
return LocalDate.ofEpochDay(getDateMillis());
}
public static void resetDate() {
Clock.time = 0;
}
private static long getDateMillis() {
return (time == 0 ? LocalDate.now().toEpochDay() : time);
}
}
And usage for it is like:
class ClockDemo {
public static void main(String[] args) {
System.out.println(Clock.getCurrentDate());
Clock.setCurrentDate(LocalDate.of(1998, 12, 12));
System.out.println(Clock.getCurrentDate());
Clock.resetDate();
System.out.println(Clock.getCurrentDate());
}
}
Output:
2019-01-03
1998-12-12
2019-01-03
Replaced all creation LocalDate.now() to Clock.getCurrentDate() in project.
Because it is spring boot application. Before test profile execution just set a predefined date for all tests:
public class TestProfileConfigurer implements ApplicationListener<ApplicationPreparedEvent> {
private static final LocalDate TEST_DATE_MOCK = LocalDate.of(...);
#Override
public void onApplicationEvent(ApplicationPreparedEvent event) {
ConfigurableEnvironment environment = event.getApplicationContext().getEnvironment();
if (environment.acceptsProfiles(Profiles.of("test"))) {
Clock.setCurrentDate(TEST_DATE_MOCK);
}
}
}
And add to spring.factories:
org.springframework.context.ApplicationListener=com.init.TestProfileConfigurer
Here's a working way to override current system time to a specific date for JUnit testing purposes in a Java 8 web application with EasyMock
Joda Time is sure nice (thank you Stephen, Brian, you've made our world a better place) but I wasn't allowed to use it.
After some experimenting, I eventually came up with a way to mock time to a specific date in Java 8's java.time API with EasyMock
Without Joda Time API
Without PowerMock.
Here's what needs to be done:
What needs to be done in the tested class
Step 1
Add a new java.time.Clock attribute to the tested class MyService and make sure the new attribute will be initialized properly at default values with an instantiation block or a constructor:
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
Inject the new attribute clock into 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 database happened before LocalDateTime.now(), which I replaced with LocalDateTime.now(clock), like so:
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
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:
import java.time.Clock;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import org.junit.Test;
public class MyServiceTest {
// (...)
private int year = 2017; // Be this a specific
private int month = 2; // date we need
private int day = 3; // to simulate.
#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 myService instance and used in the comparison instruction, and then has been properly reset to current date with initDefaultClock().
I used java.time.Clock with mockito dependency
testImplementation("org.mockito:mockito-core")
testImplementation("org.mockito:mockito-inline")
The service class uses a Clock field which will be mocked on the test.
#Service
public class TimeTestWithDateService {
private final Clock clock = Clock.systemUTC();
public TimeTest plan(UUID orderId) {
return TimeTest.builder()
.id(UUID.randomUUID())
.orderId(orderId)
.createdAt(ZonedDateTime.now(clock))
.plannedAt(ZonedDateTime.now(clock)
.plusDays(1)
.withHour(8)
.truncatedTo(ChronoUnit.HOURS))
.build();
}
public TimeTest ship(TimeTest timeTest) {
return TimeTest.builder()
.id(timeTest.getId())
.orderId(timeTest.getOrderId())
.createdAt(timeTest.getCreatedAt())
.shippedAt(ZonedDateTime.now(clock))
.build();
}
}
#Value
#Builder
public class TimeTest {
private UUID id;
private UUID orderId;
private ZonedDateTime createdAt;
private ZonedDateTime plannedAt;
private ZonedDateTime shippedAt;
}
The unit test uses the Mockito.mockStatic to mock the Clock.
#SpringBootTest
public class TimeTestWithDateServiceTest {
#Autowired
private TimeTestWithDateService timeTestService;
private static Clock clock;
private static ZonedDateTime now;
#BeforeAll
static void setupClock() {
clock = Clock.fixed(
Instant.parse("2020-12-01T10:05:23.653Z"),
ZoneId.of("Europe/Prague"));
now = ZonedDateTime.now(clock);
var clockMock = Mockito.mockStatic(Clock.class);
clockMock.when(Clock::systemUTC).thenReturn(clock);
}
#Test
void timeTest_is_planned() {
var orderId = UUID.randomUUID();
var timeTest = timeTestService.plan(orderId);
var tomorrowAt8am = now.plusDays(1).withHour(8).truncatedTo(ChronoUnit.HOURS);
assertAll(
() -> assertThat(timeTest).isNotNull(),
() -> assertThat(timeTest.getId()).isNotNull(),
() -> assertThat(timeTest.getOrderId()).isEqualTo(orderId),
() -> assertThat(timeTest.getCreatedAt()).isEqualTo(now),
() -> assertThat(timeTest.getPlannedAt()).isEqualTo(tomorrowAt8am),
() -> assertThat(timeTest.getShippedAt()).isNull()
);
}
#Test
void timeTest_is_shipped() {
var timeTest = timeTestService.plan(UUID.randomUUID());
var shipped = timeTestService.ship(timeTest);
assertAll(
() -> assertThat(shipped).isNotNull(),
() -> assertThat(shipped.getId()).isEqualTo(timeTest.getId()),
() -> assertThat(shipped.getOrderId()).isEqualTo(timeTest.getOrderId()),
() -> assertThat(shipped.getCreatedAt()).isEqualTo(timeTest.getCreatedAt()),
() -> assertThat(shipped.getShippedAt()).isEqualTo(now)
);
}
}
This example even shows how to combine Instant and LocalTime (detailed explanation of issues with the conversion)
A class under test
import java.time.Clock;
import java.time.LocalTime;
public class TimeMachine {
private LocalTime from = LocalTime.MIDNIGHT;
private LocalTime until = LocalTime.of(6, 0);
private Clock clock = Clock.systemDefaultZone();
public boolean isInInterval() {
LocalTime now = LocalTime.now(clock);
return now.isAfter(from) && now.isBefore(until);
}
}
A Groovy test
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import java.time.Clock
import java.time.Instant
import static java.time.ZoneOffset.UTC
import static org.junit.runners.Parameterized.Parameters
#RunWith(Parameterized)
class TimeMachineTest {
#Parameters(name = "{0} - {2}")
static data() {
[
["01:22:00", true, "in interval"],
["23:59:59", false, "before"],
["06:01:00", false, "after"],
]*.toArray()
}
String time
boolean expected
TimeMachineTest(String time, boolean expected, String testName) {
this.time = time
this.expected = expected
}
#Test
void test() {
TimeMachine timeMachine = new TimeMachine()
timeMachine.clock = Clock.fixed(Instant.parse("2010-01-01T${time}Z"), UTC)
def result = timeMachine.isInInterval()
assert result == expected
}
}
With the help of PowerMockito for a spring boot test you can mock the ZonedDateTime.
You need the following.
Annotations
On the test class you need to prepare the service which uses the the ZonedDateTime.
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(SpringRunner.class)
#PrepareForTest({EscalationService.class})
#SpringBootTest
public class TestEscalationCases {
#Autowired
private EscalationService escalationService;
//...
}
Test case
In the test you can prepare a desired time, and get it in response of the method call.
#Test
public void escalateOnMondayAt14() throws Exception {
ZonedDateTime preparedTime = ZonedDateTime.now();
preparedTime = preparedTime.with(DayOfWeek.MONDAY);
preparedTime = preparedTime.withHour(14);
PowerMockito.mockStatic(ZonedDateTime.class);
PowerMockito.when(ZonedDateTime.now(ArgumentMatchers.any(ZoneId.class))).thenReturn(preparedTime);
// ... Assertions
}
Use jmockit:
Code:
// Mocking time as 9am
final String mockTime = "09:00:00"
new MockUp<LocalTime>() {
#Mock
public LocalTime now() {
return LocalTime.parse(mockTime);
}
};
Imports:
import mockit.MockUp;
import mockit.Mock;
Dependency:
<groupId>org.jmockit</groupId>
<artifactId>jmockit</artifactId>
<version>1.41</version>
here is the answer : https://gabstory.com/70?category=933660
import com.nhaarman.mockitokotlin2.given
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.Mock
import org.mockito.Mockito.mockStatic
import org.mockito.junit.jupiter.MockitoExtension
import org.springframework.data.projection.ProjectionFactory
import org.springframework.data.projection.SpelAwareProxyProjectionFactory
import java.time.Clock
import java.time.ZonedDateTime
#ExtendWith(MockitoExtension::class)
class MyTest {
private val clock = Clock.fixed(ZonedDateTime.parse("2021-10-25T00:00:00.000+09:00[Asia/Seoul]").toInstant(), SEOUL_ZONE_ID)
#BeforeEach
fun setup() {
runCatching {
val clockMock = mockStatic(Clock::class.java)
clockMock.`when`<Clock>(Clock::systemDefaultZone).thenReturn(clock)
}
}
#Test
fun today(){
assertEquals("2021-10-25T00:00+09:00[Asia/Seoul]", ZonedDateTime.now().toString())
}
}
I have a function that uses the current time to make some calculations. I'd like to mock it using mockito.
An example of the class I'd like to test:
public class ClassToTest {
public long getDoubleTime(){
return new Date().getTime()*2;
}
}
I'd like something like:
#Test
public void testDoubleTime(){
mockDateSomeHow(Date.class).when(getTime()).return(30);
assertEquals(60,new ClassToTest().getDoubleTime());
}
Is it possible to mock that? I wouldn't like to change the "tested" code in order to be tested.
The right thing to do is to restructure your code to make it more testable as shown below.
Restructuring your code to remove the direct dependency on Date will allow you to inject different implementations for normal runtime and test runtime:
interface DateTime {
Date getDate();
}
class DateTimeImpl implements DateTime {
#Override
public Date getDate() {
return new Date();
}
}
class MyClass {
private final DateTime dateTime;
// inject your Mock DateTime when testing other wise inject DateTimeImpl
public MyClass(final DateTime dateTime) {
this.dateTime = dateTime;
}
public long getDoubleTime(){
return dateTime.getDate().getTime()*2;
}
}
public class MyClassTest {
private MyClass myClassTest;
#Before
public void setUp() {
final Date date = Mockito.mock(Date.class);
Mockito.when(date.getTime()).thenReturn(30L);
final DateTime dt = Mockito.mock(DateTime.class);
Mockito.when(dt.getDate()).thenReturn(date);
myClassTest = new MyClass(dt);
}
#Test
public void someTest() {
final long doubleTime = myClassTest.getDoubleTime();
assertEquals(60, doubleTime);
}
}
If you have legacy code that you cannot refactor and you do not want to affect System.currentTimeMillis(), try this using Powermock and PowerMockito
//note the static import
import static org.powermock.api.mockito.PowerMockito.whenNew;
#PrepareForTest({ LegacyClassA.class, LegacyClassB.class })
#Before
public void setUp() throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("PST"));
Date NOW = sdf.parse("2015-05-23 00:00:00");
// everytime we call new Date() inside a method of any class
// declared in #PrepareForTest we will get the NOW instance
whenNew(Date.class).withNoArguments().thenReturn(NOW);
}
public class LegacyClassA {
public Date getSomeDate() {
return new Date(); //returns NOW
}
}
You could do this by using PowerMock, which augments Mockito to be able to mock static methods. You could then mock System.currentTimeMillis(), which is where new Date() ultimately gets the time from.
You could. I'm not going to advance an opinion on whether you should.
One approach, that does not directly answer the question but might solve the underlying problem (having reproducible tests), is allow the Date as an parameter for tests and add a delegate to the default date.
Like so
public class ClassToTest {
public long getDoubleTime() {
return getDoubleTime(new Date());
}
long getDoubleTime(Date date) { // package visibility for tests
return date.getTime() * 2;
}
}
In production code, you use getDoubleTime() and test against getDoubleTime(Date date).
Working example with new Date() and System.currentTimeMillis() using PowerMockito.
Here is an example for Instance.
#RunWith(PowerMockRunner.class)
#PrepareForTest(LegacyClass.class) // prepares byte-code of the LegacyClass
public class SystemTimeTest {
private final Date fakeNow = Date.from(Instant.parse("2010-12-03T10:15:30.00Z"));
#Before
public void init() throws Exception {
// mock new Date()
PowerMockito.whenNew(Date.class).withNoArguments().thenReturn(fakeNow);
System.out.println("Fake now: " + fakeNow);
// mock System.currentTimeMillis()
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.currentTimeMillis()).thenReturn(fakeNow.getTime());
System.out.println("Fake currentTimeMillis: " + System.currentTimeMillis());
}
#Test
public void legacyClass() {
LegacyClass legacyClass = new LegacyClass();
legacyClass.methodWithNewDate();
legacyClass.methodWithCurrentTimeMillis();
}
}
class LegacyClass {
public void methodWithNewDate() {
Date now = new Date();
System.out.println("LegacyClass new Date() is " + now);
}
public void methodWithCurrentTimeMillis() {
long now = System.currentTimeMillis();
System.out.println("LegacyClass System.currentTimeMillis() is " + now);
}
}
Console output
Fake now: Fri Dec 03 16:15:30 NOVT 2010
Fake currentTimeMillis: 1291371330000
LegacyClass new Date() is Fri Dec 03 16:15:30 NOVT 2010
LegacyClass System.currentTimeMillis() is 1291371330000
you can also use jmockit to mock new Date():
#Test
public void mockTime() {
new MockUp<System>() {
#Mock
public long currentTimeMillis() {
// Now is always 11/11/2021
Date fake = new Date(121, Calendar.DECEMBER, 11);
return fake.getTime();
}
};
Assert.assertEquals("mock time failed", new Date(121, Calendar.DECEMBER, 11), new Date());
}
Date now = new Date();
now.set(2018, Calendar.FEBRUARY, 15, 1, 0); // set date to 2018-02-15
//set current time to 2018-02-15
mockCurrentTime(now.getTimeInMillis());
private void mockCurrentTime(long currTimeUTC) throws Exception {
// mock new dates with current time
PowerMockito.mockStatic(Date.class);
PowerMockito.whenNew(Date.class).withNoArguments().thenAnswer(new Answer<Date>() {
#Override
public Date answer(InvocationOnMock invocation) throws Throwable {
return new Date(currTimeUTC);
}
});
//do not mock creation of specific dates
PowerMockito.whenNew(Date.class).withArguments(anyLong()).thenAnswer(new Answer<Date>() {
#Override
public Date answer(InvocationOnMock invocation) throws Throwable {
return new Date((long) invocation.getArguments()[0]);
}
});
// mock new calendars created with time zone
PowerMockito.mockStatic(Calendar.class);
Mockito.when(Calendar.getInstance(any(TimeZone.class))).thenAnswer(new Answer<Calendar>() {
#Override
public Calendar answer(InvocationOnMock invocation) throws Throwable {
TimeZone tz = invocation.getArgumentAt(0, TimeZone.class);
Calendar cal = Calendar.getInstance(tz);
cal.setTimeInMillis(currTimeUTC);
return cal;
}
});
}
I want to mock the default constructor of java.util.date so it does not construct
a Date object representing the time when it was created, but always the same Date object (in my example below 31 Dec 2010). I tried doing this with JMockit and JUnit, but when executing my test below, the output is always Thu Jan 01 01:00:00 CET 1970. So what is wrong with my mock of Date()?
import java.util.Date;
import org.junit.*;
import mockit.*;
public class AppTest {
#Before
public void setUp() {
Mockit.setUpMocks(MockedDate.class);
}
#After
public void tearDown() {
Mockit.tearDownMocks();
}
#Test
public void testDate() {
Date today=new Date();
System.out.println(today.toString());
}
#MockClass(realClass=Date.class)
public static class MockedDate {
#Mock
public void $init() {
// Now should be always 31.12.2010!
new Date(110,11,31); //110 = 2010! 11 = December! This is sick!
}
}
}
al nik's answer was a good hint for me. It is better to mock the System class instead of the Date class to generate a fake time. My own solution in the end was simply to mock the System.currentTimeMillis() method (this method is called by Date() internally).
JMockit 1.5 and later
new MockUp<System>(){
#Mock
public long currentTimeMillis() {
// Now is always 11/11/2011
Date fake = new Date(111,10,11);
return fake.getTime();
}
};
JMockit 1.4 and earlier
#MockClass(realClass = System.class)
public static class MockedSystem {
#Mock
public long currentTimeMillis() {
// Now is always 11/11/2011
Date fake = new Date(111,10,11);
return fake.getTime();
}
}
As suggested in the Test Driven book it's good practice to use a SystemTime abstraction in your java classes.
Replace your method calls (System#currentTimeMillis and Calendar#getInstance) and direct construction (new Date()) with static method calls like:
long time = SystemTime.asMillis();
Calendar calendar = SystemTime.asCalendar();
Date date = SystemTime.asDate();
To fake the time you just need to modify what's returned by your SystemTime class.
SystemTime use a TimeSource interface that by default delegates to System.currentTimeMillis()
public interface TimeSource {
long millis();
}
a configurable SystemTime implementation could be something like this
public class SystemTime {
private static final TimeSource defaultSrc =
new TimeSource() {
public long millis() {
return System.currentTimeMillis();
}
};
private static TimeSource source = null;
public static long asMillis() {
return getTimeSource().millis();
}
public static Date asDate() {
return new Date(asMillis());
}
public static void reset() {
setTimeSource(null);
}
public static void setTimeSource(TimeSource source) {
SystemTime.source = source;
}
private static TimeSource getTimeSource() {
return (source != null ? source : defaultSrc);
}
}
and to fake the returned time you simply do
#Test
public void clockReturnsFakedTimeInMilliseconds() throws Exception {
final long fakeTime = 123456790L;
SystemTime.setTimeSource(new TimeSource() {
public long millis() {
return fakeTime;
}
});
long clock = SystemTime.asMillis();
assertEquals("Should return fake time", fakeTime, clock);
}
Joda-Time library simplifies working with dates in Java and offers you something like this out of the box
You mocked the constructor, and inside you made an instance of Date (that has nothing to do with the one constructed) and just threw it away. Since the default constructor is mocked out, date is not initialized to the current time, and so you get the time of zero (which represents 1970-01-01).
To modify the returned date you need to use a magic "it" attribute, like so:
#MockClass(realClass=Date.class)
public static class MockedDate {
public Date it;
#Mock
public void $init() {
// This is sick!
it.setDate(31);
it.setYear(110); // 110 = 2010!
it.setMonth(11); // 11 = December!
}
}
And here's a complete JUnit example based on #asmaier's great answer:
#Test
public void dateConstructorReturnsMockedDate() throws ParseException {
final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
final Date mockDate = dateFormat.parse("2002-02-02");
new MockUp<System>(){
#Mock
public long currentTimeMillis() {
return mockDate.getTime();
}
};
final Date actualDate = new Date();
assertThat(actualDate).isEqualTo(mockDate); // using AssertJ
}
When using Maven, configure JMockit as follows in pom.xml:
<dependencies>
<dependency>
<groupId>org.jmockit</groupId>
<artifactId>jmockit</artifactId>
<version>${jmockit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<argLine>
-javaagent:${settings.localRepository}/org/jmockit/jmockit/${jmockit.version}/jmockit-${jmockit.version}.jar
</argLine>
<disableXmlReport>true</disableXmlReport>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<jmockit.version>1.44</jmockit.version>
</properties>