A typical UnitTest
establishes some known initial conditions (by creating objects with known values), executes a method with known parameters, and checks whether return values and side effects match expectations. But what happens when the method uses the system date and time?
- How many days in a pay period?
- Which accounts are overdue?
- Has the credit card expired?
- What is the sale price today?
- How many days was the video rented?
One would like to control the system date and time during testing to test with a known time (or more typically several known times). However, each method that needs the current time executes system.timeNow (names vary with language). This will to DoTheSimplestThingThatCouldPossiblyWork
by letting the system code do it OnceAndOnlyOnce
but allows no control over the value of now.
(Also see the VirtualClock
Some ways that the TestOverridesNow
Having all your code call one "current time" function that you write does not
, as the system's "current time" function does not implement the required "override the clock" testing functionality.
So, implement a "system.localTimeNow" that returns a certain preset time in certain testing situations, or otherwise calls system.timeNow.
Note that the answers will change if the input (i.e. date) changes. Therefore don't change the input. Therefore don't override now. Have a method accountsOverdueOn: aDate and test that on a known date, thusly:
^accounts select: [ :each | each overdueOn: aDate]
^self accountsOverdueOn: Date today
The need to test accountsOverdueToday is, um, limited.
Tests that work with dates (and code in general) should almost never reference "now". Exceptions:
- Filling in default values in a user interface
On the contrary. In most cases, to test with known values, the input dates must in fact NOT change.
Can you give an example of this?
Why not just pass in the test date as a parameter rather than getting the system date internally? This not only makes the routine easier to test but makes for a more general method as well.
If one must leave the system date internal to the method, then test by varying one's input date. One can test with System Date - 1 day, System Date, System Date + 1 day, etc.
Or change the system clock. What, you run tests as a limited user? HaHaOnlySerious
Two words: MOCK OBJECTS. That's what they were designed for. --SamuelFalvo?
s are your friends.