Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I mock JodaTime actual date?

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

like image 359
Adriano Bacha Avatar asked Dec 15 '10 19:12

Adriano Bacha


4 Answers

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

like image 152
axtavt Avatar answered Sep 23 '22 13:09

axtavt


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).

like image 29
skaffman Avatar answered Sep 21 '22 13:09

skaffman


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.

like image 41
Behrang Avatar answered Sep 23 '22 13:09

Behrang


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...
}
like image 33
Rogério Avatar answered Sep 24 '22 13:09

Rogério