Lesson 15 of 21

Faking Time

Duration: 5:46 Watch on YouTube (external link, opens in new tab)

Markdown version

Learn a simple technique to handle time in your tests (external link, opens in new tab), and in your production code.

In this lesson

Roy Osherove explains why tests should not depend on the current date and time (external link, opens in new tab), and why extract and override (external link, opens in new tab) or a time provider interface (external link, opens in new tab) in every constructor does not suit a cross-cutting concern (external link, opens in new tab) like time. Instead he uses a static time provider class in the production code that tests can force to a given time and reset afterwards, for example in an after method. For the machine name in the next exercise he suggests extract and override.

Transcript

1,006 words

[00:02] (external link, opens in new tab) Okay, let's talk about controlling time (external link, opens in new tab) and space. One of the requirements in the document that we have is that we want to manipulate the current time. We want to format a string with a date. Now, the problem with dates are that they keep changing. So if we actually use the current date and time in our tests, what's going to happen is that every time we run the test, it's actually going to be a different test. We want our test to be repeatable always so that we can have the safe green zone (external link, opens in new tab).

[00:36] (external link, opens in new tab) If you remember, a safe green zone is when you right click and run and all the tests should be green no matter what, as long as the production code is okay. We only want them to fail when the production code is okay, not when the time changes. So instead what we want to do if we want to implement something like this but we want to test it there are several ways to get around this. For example we can create a virtual method that gets the current time.

[01:07] (external link, opens in new tab) So we can say extract method oops selected block. Oh yeah, of course. Extract method get time. And then we can make this virtual protected sorry. And then we can override it and return whatever time we want in our tests. That looks kind of easy.

[01:38] (external link, opens in new tab) However, that could be a bigger problem than you think. And the reason is because time is usually crosscutting. Everyone uses it. And so what that will require of you is that every class that uses time, you're going to have to extract and override (external link, opens in new tab) over that class. And that's going to be a big problem. So that might not be a good idea in this case. What about extracting interface? What if each class had a time provider interface (external link, opens in new tab) that it gets in the constructor? Well, you have the same problem because time is usually used in so many places.

[02:10] (external link, opens in new tab) You're going to have to inject time into so many classes, it becomes very very hard to read and maintain. Although those approaches would work, I don't think they're the best approaches in this case when we have a cross cutting concern like time. So in that kind of case, what I would do is I would actually create a time provider class, an abstraction over the current time. This is an example of what it might look like. and it can give me the current date. So I would have the current date and time.

[02:43] (external link, opens in new tab) So everyone in the production code would have to use this class. So that means that I'm changing the way people work with time and I do code reviews (external link, opens in new tab) to make sure that nobody uses date directly. But instead I want them to always use time provider which is part of the production code. But the nice thing about time provider is that I can have methods that say I want you to force the current the current time and then at the end of my test I can reset so that it sets the date to null and then it will use the current date

[03:14] (external link, opens in new tab) When someone uses it. So this is like almost like a very way a simple singleton approach to to to having time. But this abstraction actually makes our test very readable. At the beginning of our test we force the time to be something. At the end of our test we reset the time. We can even have an after method like a tear down (external link, opens in new tab) method in JUnit (external link, opens in new tab) that will reset the time automatically for all the tests. So we don't have to worry about it. And this is the case where I said that sometimes before and after methods make sense when you want to reset static stuff.

[03:47] (external link, opens in new tab) So this is an example of something that is static because we don't want to inject the time into all the instances of our of our objects. >> Yeah. So this is a good way to simulate dates. For example, you can say I want this component to to give a notification after 14 days. Then you can basically get the time provider to change the current date. Now another thing that we can do is if we if we have things that keep for example timers or time based things that change every second.

[04:20] (external link, opens in new tab) One of the ways that that we can do it is we can we can make this a bit more interesting by saying that we can get events from the time provider for example on every second that's passing and then we can trigger those events and say I want you to trigger as if 10 seconds just passed etc. So if we have eventbased objects that are listening to the current time based on the thread or something, we can instead change it directly over here. So we don't have to wait all that time. Either way, the time provider is a good abstraction in terms of design because it really removes the time away from your application and it's also good for the tests.

[04:58] (external link, opens in new tab) So what I want you to do is I want you to solve from the timebased problem onwards using a time provider. However, one of the things we'll have to do is to also get the machine name. The machine name, it could be crosscutting or it wouldn't. Usually machine name you don't get in all all in all the all the places. So machine name would be a good candidate for extract and override. So in the next scenario, you will need to fake (external link, opens in new tab) both the machine name and the time.

[05:28] (external link, opens in new tab) So you would have a combination of time provider and extract and override. they want you to to use both of them together. Okay. And after that, you can continue to future instances and you'll see that extract and override works very well for future instances as well.