Unittests - Good Test Bad Test
- Aristotle
"Quality is not an act, it is a habit."
Fundamentals
Bad tests vs. good tests
Features of a good test
Agenda
Fundamentals
testpyramid
Why Unittests?
Finding regressions in future
Improve design
Documentation
Reducing cost of change
Good test
vs.
Bad test
multiple assertions
<?php
public function testCalculation()
{
$testobj = new Calculator();
$this->assertEquals(4, $testobj->add(2, 2));
$this->assertEquals(10, $testobj->multiply(2, 5));
$this->assertEquals(3, $testobj->diversify(9, 3));
$this->assertEquals(3, $testobj->sub(7, 4));
}
?>
After a fail following assertions won't execute
Use multiple tests instead!
Dependency usage
<?php
public function testGetUsedBooks()
{
$db = new Database();
$testobj = new Library();
$testobj->load($db);
$this->assertEquals([1, 3, 5], $testobj->getUsedBooks());
}
?>
Real databases, file systems etc. will slow down and add complexity to our tests!
Use mocks instead!
# connect... select... foo...
unnecessary preconditions
<?php
public function testGetNewBooks()
{
$dbMock = new DatabaseMock();
$testobj = new Library();
$testobj->setName('MyHappyLibrary');
$testobj->load($dbMock);
$this->assertEquals([2, 4], $testobj->getNewBooks());
}
public function testAddCalculation()
{
$dbMock = new DatabaseMock();
$testobj = new Calculator();
$this->assertEquals(4, $testobj->add(2, 2));
}
?>
The code for the fixture is unnecessary or copy pasted!
Use short fixture code, the lesser the better!
# happy library, but no use...
runtime Problems
<?php
public function testGetBorrowedBooksYesterday()
{
$dbMock = new DatabaseMock([ 5 => 1494833463 ]);
$testobj = new Library();
$testobj->load($dbMock);
$date = new DateTime('now - 1 day');
$this->assertEquals([5], $testobj->getBorrowedBooks($date));
}
?>
The test will not pass on every day!
Avoid dynamic values!
<?php
public function testGetBorrowedBooksYesterdayConditional()
{
$dbMock = new DatabaseMock([ 5 => 1494833463 ]);
$testobj = new Library();
$testobj->load($dbMock);
$date = new DateTime('now - 1 day');
if ($date->getTimestamp() == 1494833463 + 86000) {
$expected = [5];
} else {
$expected = [];
}
$this->assertEquals($expected, $testobj->getBorrowedBooks($date));
}
?>
# which timestamp is it on runtime?
# does it work today?
features of a good test
testing one code unit at a time
avoid conditions
use mocking
keep preconditions clean
single assertion
Copy of Unittests - Good Test bad Test
By Martin Jainta
Copy of Unittests - Good Test bad Test
- 209