25

I want to test this method:

 public FirmOrder findActiveByModelColor(ModelColor modelColor) {
   Query query = em.createQuery("FROM FirmOrder fo WHERE fo.modelColor = :modelColor AND fo.year = :year AND fo.month = :month");
   query.setParameter("modelColor", modelColor);
   query.setParameter("year", new DateTime().year().get());
   query.setParameter("month", new DateTime().monthOfYear().get());
   return (FirmOrder) query.getSingleResult();
 }

but I need DateTime().year().get() and DateTime().dayOfMonth().get() to always return the same date

tks

Adriano Bacha
  • 1,114
  • 2
  • 13
  • 22

4 Answers4

59

If you can't add a factory object as suggested by skaffman, you can use DateTimeUtils.setCurrentMillisFixed().

axtavt
  • 239,438
  • 41
  • 511
  • 482
16

Then you need to define a Clock interface, and inject it into your class

public interface Clock {
    DateTime getCurrentDateTime();
}

then:

Clock clock;

public FirmOrder findActiveByModelColor(ModelColor modelColor) {
   Query query = em.createQuery("FROM FirmOrder fo WHERE fo.modelColor = :modelColor AND fo.year = :year AND fo.month = :month");
   query.setParameter("modelColor", modelColor);
   query.setParameter("year", clock.getCurrentDateTime().year().get());
   query.setParameter("month", clock.getCurrentDateTime().dayOfMonth().get());
   return (FirmOrder) query.getSingleResult();
 }

Your test can then inject an implementation of Clock (e.g. using a mocking framework) that always returns a fixed time.

I use the Clock interface a lot in my own stuff, and I remain surprised that it's not part of one of the common libraries out there. I have two implementations I use a lot, WallClock and StoppedClock (which is useful for tests that use a fixed time).

skaffman
  • 398,947
  • 96
  • 818
  • 769
  • I like your idea. But I have couples question that I want to ask. `Clock#getCurrentDateTime()` will return me the current `JodaTime#DateTime`, which is great. However I need to compare the current DateTime to 4PM EST. In my code, I have this `fourPM = new DateTime(current.getYear(), current.getMonthOfYear(), current.getDayOfMonth(), 16, 0, 0, 0, DateTimeZone.forID("EST"));` for `current = new DateTime()` – Thang Pham May 18 '11 at 18:00
  • @Harry: You need to ask a new question – skaffman May 18 '11 at 18:04
  • I just create a new question. http://stackoverflow.com/questions/6049777/mockito-how-to-mock-an-interface-of-jodatime Please help – Thang Pham May 18 '11 at 19:05
  • How about `clock.now()` – Bart Swennenhuis Dec 07 '14 at 20:53
  • 1
    Joda Time provides the interface [MillisProvider](http://static.javadoc.io/joda-time/joda-time/2.9.7/org/joda/time/DateTimeUtils.MillisProvider.html) for this. Default implementation is [DateTimeUtils.SYSTEM_MILLIS_PROVIDER](http://static.javadoc.io/joda-time/joda-time/2.9.7/org/joda/time/DateTimeUtils.html#SYSTEM_MILLIS_PROVIDER) – Arend v. Reinersdorff Feb 03 '17 at 17:01
  • Your wish was fulfilled in Java 8: https://docs.oracle.com/javase/8/docs/api/java/time/Clock.html – Brad Mace Jan 29 '21 at 14:17
4

Looks like the only option is to use the answer feature to post this comment:

The following portion of your code can lead to hard-to-detect errors:

query.setParameter("year", new DateTime().year().get());
query.setParameter("month", new DateTime().monthOfYear().get());

Let's pretend tha today is the last day of the year 2011 and this part of code is called 1 nano second prior to the new year and that the first statement takes more than 1 nano second to complete. This means that year will be set to 2011 but month to 1 but it had to best either to 2011/12 or 2012/1.

Though that statistically it is very unlikely to happen, but logically it can happen :)

You should create one DateTime instance and use that to populate both of year and month.

Behrang
  • 46,888
  • 25
  • 118
  • 160
  • 1
    Okay, that's not really an answer to the OP, but I upvoted it because more people need to be aware of this problem. Given that many enterprise shops (and home set-ups) do compilation during the off-hours of the night (like 11:30 PM), this bug is actually surprisingly common — and annoying. It's usually more subtle, but it's why the StoppedClock mentioned in another answer is a good idea. – Robert Fischer May 16 '12 at 00:18
1

It's easy, if using the JMockit Expectations mocking API:

@Test
public void findActiveByModelColor()
{
    new NonStrictExpectations()
    {
        @Cascading DateTime dt;

        {
            dt.year().get(); result = 2010;
            dt.monthOfYear().get(); result = 12;
        }
    };

    FirmOrder fo = testedObject.findActiveByModelColor(modelColor);

    // asserts...
}
Lukasz Stelmach
  • 5,281
  • 4
  • 25
  • 29
Rogério
  • 16,171
  • 2
  • 50
  • 63
  • So, code that uses `DateTime` (or `java.util.Date`) like this is always bad? What about code using the Apache Commons Email API, which instantiates a `SimpleEmail` object and calls `send()` on it? Is it bad code? Why? – Rogério Dec 17 '10 at 18:41