JUnit with Java 8 Clock - java

Imagine we have the following class that I would like to test:
class Times {
Clock cl = Clock.systemDefaultZone();
public int changeTime() {
LocalDate ld = LocalDate.now(cl);
if(ld.getMonth().equals(Month.OCTOBER))
return 1;
if(ld.getMonth().equals(Month.NOVEMBER))
return 2;
return 0;
}
}
How can I force the date to be in November and assert that the method returns 2?
I am using JUnit and Mockito.

Assuming there is a setter for the Clock object in Times class, you can do something like this:
Times times = new Times();
Clock fixedClockInNovember = Clock.fixed(Instant.parse("2015-11-01T00:00:00.00Z"), ZoneId.of("UTC"));
times.setClock(fixedClockInNovember);
assertEquals(2, times.changeTime());
In this code, a fixed clock is created. This simulates a constant time for the given instant, that is in November.
As such, any call to LocalDate.now(clock) will always return the same date in November.

Related

Unit testing with PowerMock, precision problem when comparing seconds

I'm trying to unit test a time function using powermock, but I'm sometimes having trouble getting through the assertEquals() when comparing the current time with system clock. The expected time is 2 seconds off. Here is my code for reference:
#RunWith(PowerMock Runner.class)
#PrepareForTest({Calendar.class, time.class})
public class TEST {
#Test
public void testTime() {
PowerMockito.mockStatic(Calendar.class);
Mockito.when(Calendar.getInstance()).thenReturn(calendarInstance);
SimpleDateFormat sdf = new SimpleDateFormat(DD_DOT_MM_DOT_YYY);
assertEquals(sdf.format(calendarInstance.getTime()), time.getDate(DD_DOT_MM_DOT_YYYY)); }
}
//inside the time.getDate function
public static String getDate(String format) {
DateFormat dateFormat = new SimpleDateFormat(format);
Date date = new Date();
return dateFormat.format(date);
}
And here's the Junit output I sometimes get which indicates the failure:
org.junit.ComparisonFailure:
Expected :20:43:18
Actual :20:43:20
I have tried a few ways to get around this, but I couldn't get it working reliably. Thank you for your help in advance.
The code sample does not show how time object in time.getDate being initialised.
For this test - you should initialise both the time and Calendar.getInstance() with same seed value else the result is unpredictable.

Java Unit Testing method that uses new Date() for current date [duplicate]

This question already has answers here:
Unit testing time-based logic in Java
(3 answers)
Handling unit tests with a condition on the current time
(6 answers)
Setting time and date in JUnit test fixture
(4 answers)
Writing and testing convenience methods using Java 8 Date/Time classes
(1 answer)
Closed 3 years ago.
So I have a class that has a method "getDaysUntil(Date date)" which returns the number of days until the date given as parameter. I mention that I cannot change the class below:
public class A {
public int getDaysUntil(Date givenDate) {
... // code
Date currentDate = new Date() //it creates a date object holding the current day
...// code that calculates the nr of days between currentDate and givenDate.
}
I have to do some unit testing and you might see the problem, it creates currentDate inside the method and the returned value will be different from day to day. I have tried to mock a Date object or "override" System.currentTimeMillis() with PowerMock but to no avail.
Is there any way to properly test these kind of methods?
Use a class that serves as a DateFactory, which is called to construct Date objects in your application code.
Then just mock the method of that DateFactory in your unit test. That way you can make it return whatever date you want as a virtual "current date"
One solution where System.currentTimeMillis() is mocked is as follows, using the JMockit library (it should be possible with PowerMock too):
#Test #SuppressWarnings("deprecation")
public void daysUntilCurrentDate() {
final long fakeCurrentDateInMillis = new Date(2017, 2, 1).getTime();
new MockUp<System>() {
#Mock long currentTimeMillis() { return fakeCurrentDateInMillis; }
};
A tested = new A();
int daysSinceJan30 = tested.getDaysUntil(new Date(2017, 1, 30));
assertEquals(2, daysSinceJan3O);
}
I understand that you cannot change the method that you need to test. Unfortunately this also means that you are stuck with the old and often not very programmer-friendly Date class (I am assuming java.util.Date).
Edit: The no-arg Date constructor that your method uses in turn uses System.currentTimeMillis(), a static native method. I didn’t know there were tools that could mock contructors and static native methods, but was informed by comment and answer by #Rogério, the developer of JMockit, that such mocking tools exist.
In any case, there is an alternative: you calculate some number of days from today, pass the resulting Date to the method and check that you get the number back you used in your calculation. This will work on any day and requires no mocking/stubbing.
In the code below I am assuming that the getDaysUntil method should discard the hours and minutes and just look at the date in the computer’s time zone. If the real requirements differ, you can probably make the appropriate adjustments to my code.
We want to take into account that the method may run over midnight. If so, I consider the result undefined since we do not know whether the Date object was constructed before or after midnight. In this case I simply try again, assuming the test will finish before the next midnight.
#Test
public void testGetDaysUntil() {
A instanceUnderTest = new A();
for (int daysToTest = 0; daysToTest <= 400; daysToTest++) {
LocalDate today;
int result;
do {
today = LocalDate.now(); // do this in each iteration in case day changes underway
LocalDate targetDate = today.plusDays(daysToTest);
Date midnightAtStartOfDay = Date.from(targetDate.atStartOfDay(ZoneId.systemDefault())
.toInstant());
result = instanceUnderTest.getDaysUntil(midnightAtStartOfDay);
} while (! today.equals(LocalDate.now())); // if we have passed midnight, try again
assertEquals(daysToTest, result);
do {
today = LocalDate.now();
LocalDate targetDate = today.plusDays(daysToTest);
Date nearMidnightAtEndOfDay = Date.from(targetDate.atTime(23, 59, 59, 400_000_000)
.atZone(ZoneId.systemDefault())
.toInstant());
result = instanceUnderTest.getDaysUntil(nearMidnightAtEndOfDay);
} while (! today.equals(LocalDate.now()));
assertEquals(daysToTest, result);
}
}
I have used the Java 8 classes for the date and time calculations. If you cannot use Java 8, Calendar and/or GregorianCalendar can be used, they may be just a little more cumbersome for this job, but at least can be converted to Date easily.

JUnit test method comparing DateTimes fails only when run from suites

A single JUnit test being run under JUnit 4.11 fail the majority of the time while being run via either to module test suite (40 runs: 2 failures, 38 passes), or the class test suite (40 runs: 6 failures, 34 passes), but running the test method by itself did not produce a single failure (50 runs: 0 failures, 50 passes).
To summarize what is happening, the equals(Object MyObject) implementation returns true if the org.joda.time.DateTime corresponding to the key Stamp.START or the key Stamp.STOP is the same for the current instance as the one in instance passed to the method. Here's the code:
import org.joda.time.DateTime;
...
private final Map<Stamp, DateTime> timeStampMap;
...
#Override
public boolean equals(Object obj) {
if (this == obj) { return true; }
if (obj == null || getClass() != obj.getClass()) { return false; }
final MyObject other = (MyObject) obj;
return (Objects.equals(this.timeStampMap.get((Stamp.START)),
other.timeStampMap.get(Stamp.START))
&& Objects.equals(this.timeStampMap.get(Stamp.STOP),
this.timeStampMap.get(Stamp.STOP)));
}
...
public enum Stamp {
START,
STOP
}
And the test itself:
#Test
#Config(configuration = TestConfig.NO_CONFIG)
public void equalityTest() {
MyObject a = new MyObject(BigDecimal.TEN);
MyObject b = a;
assertThat(a.hashCode(), is(b.hashCode()));
assertTrue(a.equals(b));
b = new MyObject(BigDecimal.TEN);
// This line produces the failure
assertThat(a, is(not(b)));
}
Why would this test only fail when run under either test suite, but not when run on it's own?
Since you are using Joda time, an alternative approach might be to fix the current time to something of your choosing using DateTimeUtils.setCurrentMillisFixed(val).
For example:
#Test
#Config(configuration = TestConfig.NO_CONFIG)
public void equalityTest() {
DateTimeUtils.setCurrentMillisFixed(someValue);
MyObject a = new MyObject(BigDecimal.TEN);
MyObject b = a;
assertThat(a.hashCode(), is(b.hashCode()));
assertTrue(a.equals(b));
DateTimeUtils.setCurrentMillisFixed(someValue + someOffset);
b = new MyObject(BigDecimal.TEN);
// This line produces the failure
assertThat(a, is(not(b)));
}
I suggest making the code more testable. Instead of having the code get the date directly, you can pass in an interface named Clock:
public interface Clock {
DateTime now();
}
Then you could add Clock to the constructor:
MyObject(BigDecimal bigDecimal, Clock clock) {
timeStampMap.put(Stamp.START, clock.now());
}
For production code, you can make a helper constructor:
MyObject(BigDecimal bigDecimal) {
this(bigDecimal, new SystemClock());
}
...where SystemClock looked like this:
public class SystemClock implements Clock {
#Override
public DateTime now() {
return new DateTime();
}
}
Your tests could either mock Clock or you could create a fake clock implementation.
Over the process of trying to produce an MCVE and author the question, I discovered something interesting:
When the test is run at the method level, note the timestamp difference of 1 millisecond. The difference is never less than that:
[START: 2015-02-26T11:53:20.581-06:00, STOP: 2015-02-26T11:53:20.641-06:00, DURATION: 0.060]
[START: 2015-02-26T11:53:20.582-06:00, STOP: 2015-02-26T11:53:20.642-06:00, DURATION: 0.060]
But when I run the test ends up being run as part of the suites, this happens nearly every single time:
[START: 2015-02-26T12:25:31.183-06:00, STOP: 2015-02-26T12:25:31.243-06:00, DURATION: 0.060]
[START: 2015-02-26T12:25:31.183-06:00, STOP: 2015-02-26T12:25:31.243-06:00, DURATION: 0.060]
Zero difference. Weird right?
My best guess is that the JVM is proverbially all warmed up and has some momentum built by the time it reaches this particular test when running the test suites. So much so, that the instantiations occur so quickly as to be nearly simultaneous. The tiny amount of time that passes between the time that MyObject a is instantiated and b is assigned until b is reassigned as a new MyObject is so minute as to produce a MyObject with an identical pair of DateTimes.
Turns out, there are a few usable solutions:
The Solution I Went With:
This is really similar to Duncan's. Call DateTimeUtils.setCurrentMillisOffset(val) before reassigning MyObject b and then reset immediately afterward, since I only need the offset long enough to force a difference in the DateTimes between MyObjects a and b:
#Test
#Config(configuration = TestConfig.NO_CONFIG)
public void equalityTest() {
MyObject a = new MyObject(BigDecimal.TEN);
MyObject b = a;
assertThat(a.hashCode(), is(b.hashCode()));
assertTrue(a.equals(b));
// Force an offset
DateTimeUtils.setCurrentMillisOffset(1000);
b = new MyObject(BigDecimal.TEN);
// Clears the offset
DateTimeUtils.setCurrentMillisSystem();
assertThat(a, is(not(b)));
}
Namshubwriter's Solution (link to answer):
Easily the best solution in cases where this issue will likely be seen throughout a project and/or in actual use.
Duncan's Solution (link to answer):
Set the current time to return a fixed time by calling DateTimeUtils.setCurrentMillisFixed(val) at the beginning of the unit test, then adding an offset to that time by calling DateTimeUtils.setCurrentMillisFixed(val + someOffset) to force the difference before reassigning MyObject b. Click the link to jump right to his solution with the code.
It is worth pointing out that you'll need to call DateTimeUtils.setCurrentMillisSystem() at some point to reset the time, otherwise other tests dependent on the time could be affected.
Original Solution:
I think it is worth mentioning here that, it is my understanding this is the only solution that does not depend on the program having certain security privileges on the parent system.
Place a call to Thread.sleep() ensure that there is a time separation between the DateTime timestamps of the two MyObjects:
#Test
#Config(configuration = TestConfig.NO_CONFIG)
public void equalityTest() {
MyObject a = new MyObject(BigDecimal.TEN);
MyObject b = a;
assertThat(a.hashCode(), is(b.hashCode()));
assertTrue(a.equals(b));
try {
Thread.sleep(0, 1);
} catch (Exception e) {
e.printStackTrace();
}
b = new MyObject(BigDecimal.TEN);
// Line that was failing
assertThat(a, is(not(b)));
}

Does Joda-Time have a method called isToday

I need to check if a given timestamp is today. I am using Joda-Time. Is there a method or a simple way to check this? What Joda-Time class is better suited for this? LocalDate? DateTime?
The date can be compared by single statement so why you need a special function.
when dateTimeis an object of DateTime()
if((dateTime.toLocalDate()).equals(new LocalDate()))
when date is an object of java.util.date
if((new DateTime(date).toLocalDate()).equals(new LocalDate()))
What Joda-time class is better suited for this? LocalDate? DateTime?
The understanding that you need to know what is LocalDate and DateTime.
LocalDate() is an immutable datetime class representing a date without a
time zone. So is not having a time part.
DateTime() is the standard implementation of an unmodifiable datetime
class. Its having all the attributes of the Date, which includes
date, time and timezone.
So if you need to compare both the date and time better go with datetime, if you just need to check the date you must use localDate because the datetime will produce a false if an .equal operator is used, unless the time including the seconds part are same for both the objects.
Here are some simple methods to check if a DateTime is today, tomorrow or yesterday:
public boolean isToday(DateTime time) {
return LocalDate.now().compareTo(new LocalDate(time)) == 0;
}
public boolean isTomorrow(DateTime time) {
return LocalDate.now().plusDays(1).compareTo(new LocalDate(time)) == 0;
}
public boolean isYesterday(DateTime time) {
return LocalDate.now().minusDays(1).compareTo(new LocalDate(time)) == 0;
}
One possibility is to create an interval covering the whole day in question, and then check if the various timestamps are contained in this interval.
Constructing the initial interval could look like:
Interval today = new Interval(DateTime.now().withTimeAtStartOfDay(), Days.ONE);
Then the timestamps could be checked like so:
today.contains(DateTime.now()); // True
today.contains(DateTime.now().minusDays(1)); // False
today.contains(DateTime.now().plusDays(1)); // False
today.contains(someOtherTimeStamp.toDateTime()); // And so on...
The recommended way to do this would be:
DateTime midnightToday = DateTime.now().withTimeAtStartOfDay();
DateTime myDateTime = <whatever>;
if(myDateTime.isAfter(midnightToday)) {
}
I think you need Joda 2.5 to do this, but that should do the trick.
I like #JustinMorris's answer. But I found this even better:
public static boolean isToday(DateTime time) {
return LocalDate.now().equals(new LocalDate(time));
}
public static boolean isTomorrow(DateTime time) {
return LocalDate.now().plusDays(1).equals(new LocalDate(time));
}
public static boolean isYesterday(DateTime time) {
return LocalDate.now().minusDays(1).equals(new LocalDate(time));
}
AFAIK there is no direct method available by which you can check the Date is Today Date or not.
The simplest approach will be constructing two DateTime one with the Timestamp, and another with today Date and then comparing day from dayOfYear() and year from year() but do remember whether both Date are in UTC or in Local Time Zone.
A small sample,
DateTime date = new DateTime(TimeStamp);
DateTime todayDate = new DateTime();
if(date.dayOfYear().get() == todayDate.dayOfYear().get() && date.year().get() == todayDate.year().get())
{
System.out.println("Date is today date");
}
Joda time actually have a method for this:
DateUtils#isToday(ReadablePartial);
DateUtils#isToday(ReadableInstant);
Simplest way I've found:
public boolean isToday(DateTime dateTime) {
return dateTime.withTimeAtStartOfDay().getMillis() ==
new DateTime().withTimeAtStartOfDay().getMillis();
}

How to hold a value on java

This is my first month on java. I got a logical error that updates the this value each time I call the method.How can I fix this and make static so each time the original data and time is not change.
result:
testing 7 arg constructor with initial date: [2-28-2015],[12:30:30:0]
Increasing day by 366 [2-29-2016],[12:30:30:0]
Increasing month by 12 [2-28-2017],[12:30:30:0]<---- should be 2016
Increasing year by 2 [2-28-2019],[12:30:30:0]<-------should be 2017
Initial date is [2-28-2016],[12:30:30:0]
Increasing day by 365 [2-27-2017],[12:30:30:0]
Increasing month by 11 [1-27-2018],[12:30:30:0]
Increasing year by 30 [1-27-2048],[12:30:30:0]
here is my code:
public class DateTime implements DateConstants {
private Date date; // from Date Class
private Time time; // from Time class
}
public DateTime addMonths(int mo)
{
this.date.addMonths(mo);
return this;
}
public static void main(String[] myArgs) {
dateTime1 = new DateTime(2,28,2015,12,30,30,0);
System.out.println("testing 7 arg constructor with initial date: "+dateTime1);
System.out.println("Increasing day by 366 "+dateTime1.addDays(366));
System.out.println("Increasing month by 12 "+dateTime1.addMonths(12));
System.out.println("Increasing year by 2 "+dateTime1.addYears(2));
}
If I'm understanding you correctly, you want your additions to add to the base value that the object was created with. Right now, you have one object that is maintaining its state through execution, so when you say dateTime1.addDays(366), it's modifying that object permanently.
You'll have to either put in functionality to hold onto the values passed into the constructor to "reset" to, or re-instantiate the DateTime object after every modification.
As others have said, there is a meaning to the word static, and this is not appropriate. Please change your title.
if i understand correctly your question, I think you can try this
public class DateTime implements DateConstants {
private Date date; // from Date Class
private Time time; // from Time class
}
public DateTime addMonths(int mo)
{
DateTime temp=this.clone();
return temp.date.addMonths(mo);
}
public static void main(String[] myArgs) {
dateTime1 = new DateTime(2,28,2015,12,30,30,0);
System.out.println("testing 7 arg constructor with initial date: "+dateTime1);
System.out.println("Increasing day by 366 "+dateTime1.addDays(366));
System.out.println("Increasing month by 12 "+dateTime1.addMonths(12));
System.out.println("Increasing year by 2 "+dateTime1.addYears(2));
}
if you re-create the object before each system.out, you'll get the result you want.
it seems that your object is being reused
The declaration of "dateTime1" is missing from your code, and then we assume it´s a class attribute, but you should show in your question where it is declared.

Categories