January 17, 2012

Mocking with JodaTime's DateTime and Google Guava's Supplier

 

Introduction

If you're a seasoned unit tester, you've learned to take note when you see any code working with time, concurrency, random, persistence and disc I/O.

The reason for this is that tests can be very brittle and sometimes down-right impossible to test properly. This post will show how to abstract out "time" by injecting a replacement for it in the consumer.  This post will be using Spring 3 as the Dependency Injection container, though Guice, other DI containers or constructor/setters on POJOs would work as well.  I will also ignore Locales since the focus is on the injection of the DateTime, not DateTime itself.

Existing code

You've been handed a piece of code to unit test (or you are creating one and this is your first stab at it).  Our first piece of code, only one class: (This class is a Spring 3.1 controller and the purpose is to return back the current time as a String)

@Controller
@RequestMapping(value = "/time")
@VisibleForTesting
class TimeController {

    @RequestMapping(value = "/current", method = RequestMethod.GET)
    @ResponseBody
    public String showCurrentTime() {
        // BAD!!! Can't test
        DateTime dateTime = new DateTime();
        return DateTimeFormat.forPattern("hh:mm").print(dateTime);
    }
}

Take note that the class does a "new DateTime()" in the class.  Here is the corresponding test class:

What happens when we run the test?  How about assuming we have a very slow machine. You could (and most likely will) end up with your comparison DateTime to be different than the returned DateTime. This is a problem!

First thing to do is to remove the dependency, but how are we going to do this?  If we make the DateTime a field on the class, we will still have the same problem.  Introduce Google Guava's Supplier interface.


Google Guava Supplier

The Supplier interface only has one method, "get()" which will return an instance of whatever the supplier is setup for.  An example, the supplier will return a user's first name if they have logged in, and a default one if they have not:

public class FirstNameSupplier implements Supplier<String> {

    private String value;
    private static final String DEFAULT_NAME = "GUEST";

    public FirstNameSupplier() {
        // Just believe that this goes and gets a User from somewhere
        String firstName = UserUtilities.getUser().getFirstName();
        // more Guava
        if(isNullOrEmpty(firstName)) {
            value = DEFAULT_NAME;
        } else {
            value = firstName;
        }
    }

    @Override
    public String get() {
        return value;
    }
}

To your implementing method, you don't care what the first name is, only that you get one.


Refactoring out DateTime

Let's move on. For a much more real example of using a Supplier (and the point of this post) let's implement a DateTime supplier to give us back the current DateTime. While we're at it, let's also create an interface so that we can create mock implementations for testing:

public interface DateTimeSupplier extends Supplier<DateTime> {
    DateTime get();
}

and an implementation:

public class DateTimeUTCSupplier implements DateTimeSupplier {
    @Override
    public DateTime get() {
        return new DateTime(DateTimeZone.UTC);
    }
}

Now we can take the DateTimeUTCSupplier and inject that into our code that needs the current DateTime as the DateTimeSupplier interface:

@Controller
@RequestMapping(value = "/time")
@VisibleForTesting
class TimeController {

    @Autowired
    @VisibleForTesting
    // Injected DateTimeSupplier
    DateTimeSupplier dateTime;

    @RequestMapping(value = "/current", method = RequestMethod.GET)
    @ResponseBody
    public String showCurrentTime() {
        return DateTimeFormat.forPattern("hh:mm").print(dateTime.get());
    }
}

In order to test this, we'll need to create a MockDateTimeSupplier and have a controller to pass in the specific instance we want to return:

public class MockDateTimeSupplier implements DateTimeSupplier {

    private final DateTime mockedDateTime;

    public MockDateTimeSupplier(DateTime mockedDateTime) {
        this.mockedDateTime = mockedDateTime;
    }

    @Override
    public DateTime get() {
        return mockedDateTime;
    }
}

Notice that the object being saved is passed in via the constructor. This will not get you the current date/time back, but will return back the specific instance you want

and finally our test that exercises (slightly) the TimeController we implemented above:

public class TimeControllerTest {

    private final int HOUR_OF_DAY = 12;
    private final int MINUTE_OF_DAY = 30;

    @Test
    public void testShowCurrentTime() throws Exception {
        TimeController controller = new TimeController();
        // Create the mock DateTimeSupplier with our known DateTime
        controller.dateTime = new MockDateTimeSupplier(new DateTime(2012, 1, 1, HOUR_OF_DAY, MINUTE_OF_DAY, 0, 0));

        // Call our method
        String dateTimeString = controller.showCurrentTime();

        // Using hamcrest for easier to read assertions and condition matchers
        assertThat(dateTimeString, is(String.format("%d:%d", HOUR_OF_DAY, MINUTE_OF_DAY)));
    }

}

Conclusion

This post has shown how to use Google Guava's Supplier interface to abstract out a DateTime object so you can better design your implementations with unit testing in mind! Suppliers are a great way to solve the "just give me something", mind you it's a known type of something.


Good luck!

46 comments:

eneveu said...
This comment has been removed by the author.
eneveu said...

[trying again with proper HTML escaping]

Cool post.

Couldn't you avoid creating a DateTimeSupplier interface, and instead inject a Supplier directly?

@Autowired
@VisibleForTesting
Supplier<DateTime> dateTime;

In which case you wouldn't need the MockDateTimeSupplier class, and could instead do:

controller.dateTime = Suppliers.ofInstance(new DateTime(2012, 1, 1, HOUR_OF_DAY, MINUTE_OF_DAY, 0, 0));

Or would Spring's autowiring fail because it would have to inject a "generified bean" (Supplier), and the type info would be gone at runtime?

Anonymous said...

So you just described the factory pattern... no big deal

without having read the javadoc... is there more to the Supplier Interface than just being a predefined Factory interface?

Unknown said...

Hey Anonymous,

You're right, the Guava Supplier is a typed factory at it's core, but the main functionality comes from the ability to guarantee an result/object, pass and transform input and return Functions to be used within an algorithm.

This blog post is not specifically about Supplier interface, the blog post is about a possible solution to dealing with Dates and how to test them.

You've identified the pattern used here so probably know, almost all solutions involve at least one pattern from the original Gang of Four book. The point of this blog is not to show off brand new code for every solution, it is to share solutions to problems common to all developers and often times I find the simplest solution is to use existing open source software. I chose to use a Supplier instead of creating my own Factory pattern comes down to the "Don't repeat yourself" principal that every developer should know and love. Why re-write something that someone else has written and has been tested by tens of thousands of developers world wide?

I would suggest you read the JavaDocs on Supplier and while you're at it, many of the other amazing library additions to the Guava project (I use ImmutableList/ImmutableMap, Multimaps, Iterators, Strings, @VisibleForTesting, and many more)

Posting a comment with flame-tones in it does not help the community share information, nor does it foster an "ask anything, there are no stupid questions" attitude that I have tried to build. In the future, if you would like to flame a posting, please visit Facebook, Reddit or Twitter

Mike!

Anonymous said...

Jodatime provides methods to "stop" the time in the class. http://joda-time.sourceforge.n.... Constructors use the methods in this class to initialize their fields. This can be useful for unit test without modifying the original code. Method to use setCurrentMillisFixed.

Anonymous said...

Sorry I forget name of class DateTimeUtils and link http://joda-time.sourceforge.net/apidocs/org/joda/time/DateTimeUtils.html

Unknown said...

Hi Mike,
Thanks for your post and explications. I don't understand exactly which is the advantage of using Supplier interface? From my point of view the only advantage is that we can use the injection directly, we are forced to implement the get() method, if there are other advantage please light me :). Thanks.

Unknown said...

I'll try to address these separately. First, setCurrentMillisFixed with the JodaTime constructors for dates is a solution, and while it is tread safe, it isn't parallelizable for tests. If you run tests concurrently and modify the system date in one test, you can't guarantee that the test will use the system date for that specific test case. This is why I recommend creating an abstraction for dates when creating calculations. Another possible strategy would be to pass around Intervals (I'm considering writing a post on that).

@sorin cristea, the Supplier interface is a very generic factory pattern (or some would like to call it a no-argument function). The advantages would be if you wanted to maybe look up a date from a database, if it isn't a suitable date, then return a default. The possibilities are pretty much endless on what you can use the Supplier for, I tend to think of it as (from the class level) "I don't really care where/how I will be getting this, but I can expect to get a workable object"

Mike!

for ict 99 said...

Hi, Great.. Tutorial is just awesome..It is really helpful for a newbie like me.. I am a regular follower of your blog. Really very informative post you shared here. Kindly keep blogging. If anyone wants to become a Java developer learn from Java Training in Chennai. or learn thru Java Online Training India . Nowadays Java has tons of job opportunities on various vertical industry.

Unknown said...

I feel really happy to have seen your webpage and look forward to so many more entertaining times reading here. Thanks once more for all the details.


java training in bangalore
java training in bangalore

Nandhu said...

its very useful for us. more helpful. i really appreciate you to do and shared this kind of helpful blog with us.
Photoshop Training Institute in Chennai | Photoshop Training Institute in Velachery

Sarath K said...

Your blog is awesome..Your blog is explain each and every concept is good...
CorelDraw Training Institute in Chennai | Photoshop Training Institute in Chennai | CorelDraw Training Institute in Velachery

Unknown said...

You are right, blogging teaches you a lot about yourself...
Best Photoshop Training Institute in Chennai | CorelDraw Training Institute in Chennai | No.1 Photoshop Training Institute in Velachery

Unknown said...

Appreciation for really being thoughtful and also for deciding on certain marvelous guides most people really want to be aware of.

AWS Training in Chennai

krish said...

Needed to compose you a very little word to thank you yet again regarding the nice suggestions you’ve contributed here.
Good Graphics Designing Training Institute in Chennai | Best Multimedia Training Institute in Velachery

Ed Sheeran said...

wow really nice and useful article and explanation are very clear so easy to understand.. thanks a lot for sharing.
Photoshop Training Institute in Chennai | Best Multimedia Training Institute in Velachery

Unknown said...

Good job in presenting the correct content with the clear explanation. The content looks real with valid information. Good Work

DevOps is currently a popular model currently organizations all over the world moving towards to it. Your post gave a clear idea about knowing the DevOps model and its importance.

Good to learn about DevOps at this time.


devops training in chennai | devops training in chennai with placement | devops training in chennai omr | devops training in velachery | devops training in chennai tambaram | devops institutes in chennai | devops certification in chennai | trending technologies list 2018

Unknown said...

Looking for the best online casino games? Come to us at BGAOC and win now perfect internet slots Luck will smile at you immediately.

VenuBharath2010@gmail.com said...

Amazing Post. The content is very interesting. Waiting for your future updates.
Xamarin Training in Chennai
Xamarin Course in Chennai
Xamarin Training
Xamarin Course
Primavera Training in Chennai
Primavera Course in Chennai
IELTS coaching in Chennai
IELTS Training in Chennai

pavithra dass said...

Thanks for splitting your comprehension with us. It’s really useful to me & I hope it helps the people who in need of this vital information.
Java Training in Chennai
Java course in Chennai
Software Testing Training in Chennai
Web Designing Course in chennai
PHP Training in Chennai
Java Training in Tambaram
Java Training in OMR

jorick228 said...

Interested in details on online casinos? Come to us, here is all in full details. Top online casinos in the world Best casino only at BGAOC.

Belago said...

Я бы рекомендовал использовать профиль для светодиодных лент это нужно для того что бы лента дольше служила.

Maria said...

I started playing at simply real casino games after reading reviews from other players and I see that it’s not for nothing. Judging by the number of reviews on the Internet, it seems that only the lazy one did not play here)) Well, by the number of reviews and topics on the forums one can definitely say that this is one of the most popular players.

service care said...

I think this is a great site to post and I have read most of contents and I found it useful for my Career .Thanks for the useful information. Good work.Keep going.
motorola service center near me
motorola mobile service centre in chennai
moto g service center in chennai

spot said...

super your blog
andaman tour packages
andaman holiday packages
web development company in chennai
Math word problem solver
laptop service center in chennai
Austin Homes for Sale

anitha said...

Excellent Post. Extra-ordinary work to share with. Thanks for posting.
Node JS Training in Chennai
Node JS Course in Chennai
Node JS Advanced Training
Node JS Training Institute in chennai
Node JS Training in Velachery
Node JS Training in Tambaram
Node JS Training in OMR
Node JS Training in T Nagar

DedicatedHosting4u said...


Just seen your Article, it amazed me and surpised me with god thoughts that eveyone will benefit from it. It is really a very informative post for all those budding entreprenuers planning to take advantage of post for business expansions. You always share such a wonderful articlewhich helps us to gain knowledge .Thanks for sharing such a wonderful article, It will be deinitely helpful and fruitful article.
Thanks
DedicatedHosting4u.com

shivam said...

Flying Shift - Packers & Movers in Bhopal

Tech News said...

Nice blog
Visit here - BIG DATA AND HADOOP TRAINING IN BANGALORE

event management said...

Thanks for sharing this valuable information with us..
wedding photographers in chennai

impressbss said...

Thank you for providing useful article.
web design company in chennai

Prwatech said...

I learned World's Trending Technology from certified experts for free of cost. I Got a job in decent Top MNC Company with handsome 14 LPA salary, I have learned the World's Trending Technology from python training in btm layout experts who know advanced concepts which can help to solve any type of Real-time issues in the field of Python. Really worth trying instant approval blog commenting sites

INTRADOTE (**OFFICIAL**) said...

tndte

Stephie John said...

Hi Thank you for such a nice article. Best website development company Keep posting.

Mahi said...

Wow it is really wonderful and awesome thus it is very much useful for me to understand many concepts and helped me a lot.

Online Training in bangalore

courses in bangalore

classes in bangalore

Online Training institute in bangalore

course syllabus

best Online Training

Online Training centers

Mahi said...

I recently came across your article and have been reading along. I want to express my admiration of your writing skill and ability to make readers read from the beginning to the end. I would like to read newer posts and to share my thoughts with you.

Mulesoft training in bangalore

Mulesoft class in bangalore

learn Mulesoft in bangalore

places to learn Mulesoft in bangalore

Mulesoft schools in bangalore

Mulesoft reviews in bangalore

Mulesoft training reviews in bangalore

Mulesoft training in bangalore

Mulesoft institutes in bangalore

Mule soft trainers in bangalore

learning Mule soft in bangalore

where to learn Mule soft in bangalore

best places to learn Mule soft in bangalore

top places to learn Mule soft in bangalore

Mule soft training in bangalore india

Mahi said...

Such a very useful article. Very interesting to read this article.I would like to thank you for the efforts you had made for writing this awesome article.

MongoDB Online Training

MongoDB Classes Online

MongoDB Training Online

Online MongoDB Course

MongoDB Course Online

Mahi said...

Very interesting blog Thank you for sharing such a nice and interesting blog and really very helpful article.

Sap Solution Manager Online Training

Sap Solution Manager Classes Online

Sap Solution Manager Training Online

Online Sap Solution Manager Course

Sap Solution Manager Course Online

nisharoshan said...

Thank you for the informative post. It was thoroughly helpful to me. Keep posting more such articles and enlighten us.

Web Designing Training Course in Chennai | Certification | Online Training Course | Web Designing Training Course in Bangalore | Certification | Online Training Course | Web Designing Training Course in Hyderabad | Certification | Online Training Course | Web Designing Training Course in Coimbatore | Certification | Online Training Course | Web Designing Training Course in Online | Certification | Online Training Course

Jayalakshmi said...

Wow it is really wonderful and awesome thus it is very much useful for me to understand many concepts and helped me a lot.
angular js training in chennai

angular js training in tambaram

full stack training in chennai

full stack training in tambaram

php training in chennai

php training in tambaram

photoshop training in chennai

photoshop training in tambaram

deiva said...

nice blog..
web designing training in chennai

web designing training in omr

digital marketing training in chennai

digital marketing training in omr

rpa training in chennai

rpa training in omr

tally training in chennai

tally training in omr

praveen said...

Hi it's really informative blog ,
Thanks to share with us,

https://www.porurtraining.in/hardware-and-networking-training-in-porur-chennai
https://www.porurtraining.in/xamarin-training-in-porur-chennai
https://www.porurtraining.in/ios-training-in-porur-chennai
https://www.traininginvelachery.org/iot-training-in-velachery-chennai

jeni said...

i never know the use of adobe shadow until i saw this post. thank you for this! this is very helpful.
hadoop training in chennai

hadoop training in velachery

salesforce training in chennai

salesforce training in velachery

c and c plus plus course in chennai

c and c plus plus course in velachery

machine learning training in chennai

machine learning training in velachery


shiny said...

So Informative and useful blog.

web designing training in chennai

web designing training in annanagar

digital marketing training in chennai

digital marketing training in annanagar

rpa training in chennai

rpa training in annanagar

tally training in chennai

tally training in annanagar

vivekvedha said...

its very useful for us. more helpful. i really appreciate you to do and shared this kind of helpful blog with us.
acte chennai

acte complaints

acte reviews

acte trainer complaints

acte trainer reviews

acte velachery reviews complaints

acte tambaram reviews complaints

acte anna nagar reviews complaints

acte porur reviews complaints

acte omr reviews complaints


Mohd Sharique said...

Great Blog to read,Its gives more useful information.Thank lot.

Python Training In Pune
python training institute in pune