Code Review: Dates in unit tests
One of the things about reviewing code is how often I can look at code and think that it ios pretty good only to have it fail and on review discovering that the failure has an obvious fix.
I had a unit test like this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Before
fun before_each_test() {
createInMemoryDatabase()
trackRepository = TrackRepository(loggerFactory, dbHelper)
track1 = Track()
track1.name = "NAME1"
date1 = Calendar.getInstance()
date1.set(2019, 1, 29, 11, 3, 33)
track1.started = date1
track2 = Track()
track2.name = "NAME2"
date2 = Calendar.getInstance()
date2.set(2019, 11, 30, 15, 37, 22)
}
@Test
fun create_getTrackList() {
// arrange
track1 = trackRepository.create(track1)
// act
var result = trackRepository.getTrackList(positionRepository)
// assert
// we get a brand new DB for each test so we know how the IDs are generated
Assert.assertEquals(2, result.count())
Assert.assertEquals("the list should be reverse sorted by date", 2, result[0].id)
Assert.assertEquals("the list should be reverse sorted by date", 1, result[1].id)
}
This test was working fine - well it wasnt really - until it suddenly started failing in February this year. I was very confused as the failure coincided with me doing some work on the TrackRepository
class.
After some debugging I worked out that the mistake was there was a missing line - the last line of the setup method was missing, either accidentally deleted or never written it should have set the started
property of track2
like so
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Before
fun before_each_test() {
createInMemoryDatabase()
trackRepository = TrackRepository(loggerFactory, dbHelper)
track1 = Track()
track1.name = "NAME1"
date1 = Calendar.getInstance()
date1.set(2019, 1, 29, 11, 3, 33)
track1.started = date1
track2 = Track()
track2.name = "NAME2"
date2 = Calendar.getInstance()
date2.set(2019, 11, 30, 15, 37, 22)
track2.started = date2
}
The reason the test passed was that the default value for started
was now
, this is not uncommon in many libraries and languages. This meant that while now
was before the end of January 2019 getTrackList
returned them in the order track2
and then track1
because until the end of January track1
occured before track2
, however as soon as we crossed that date the test failed.
This is because if you use dates in the future in your tests then at some point they will become dates in the past. If you only use dates that are in the past then they will stay in the past. Your test may be wrong - as mine was - but it will not be unstable because of the current date. I think having stable tests is more desirable, doing red/green refactoring would drive out the faulty test.