I've recently started using unit tests and it's been a blast so far.
However, I've bumped into a situation where my approach feels plain wrong and I can't wrap my head around a "good" solution.
The context for the code is an application for viewing tv broadcast schedules written in symfony, tested with sfPHPUnit2Plugin.
public function testLoadChannelBroadcasts() {
$Start = new DateTime();
$End = new DateTime();
$Channels = ChannelTable::getChannelsWithBroadcastsTouchingTimeSpan($Start, $End);
foreach ($Channels as $Channel) {
$Channel->loadBroadcastsTouchingTimeSpan($Start, $End);
}
// test data
$Broadcasts = $Channels[0]->Broadcasts;
$assertion = $Broadcasts[0]->getDateTimeObject('start') <= $Start
&& $Broadcasts[0]->getDateTimeObject('end') >= $Start;
$this->assertTrue($assertion, 'starts before scope, ends inside scope');
$assertion = $Broadcasts[1]->getDateTimeObject('start') >= $Start
&& $Broadcasts[1]->getDateTimeObject('end') <= $End;
$this->assertTrue($assertion, 'starts inside scope, ends inside scope');
$assertion = $Broadcasts[2]->getDateTimeObject('start') >= $Start
&& $Broadcasts[2]->getDateTimeObject('end') >= $End;
$this->assertTrue($assertion, 'starts inside scope, ends outside scope');
$LongBroadcast = $Channels[1]->Broadcasts[0];
$assertion = $LongBroadcast->getDateTimeObject('start') <= $Start
&& $LongBroadcast->getDateTimeObject('end') >= $End;
$this->assertTrue($assertion, 'starts before scope, ends after scope');
}
The test communicates the purpose of the method, but the testing of data (fixtures) relies heavily on assumptions about what the data contains. Is there a better approach to this?
This is not really a unit test as it is right now, because you are testing the method outside its boundaries, by calling ChannelTable
.
The proper way of doing this would be to change:
$Channels = ChannelTable::getChannelsWithBroadcastsTouchingTimeSpan($Start, $End);
To:
$Channels = array('yourdata', 'etc');
This way, if ChannelTable
fails to provide the correct data, your test doesn't fail, because it shouldn't.
Remember, a unit test purpose is to test the unit (method) and nothing else. If your whole application fails to connect to a database and provide data, the unit test still passes because the method behaves as it should.