🇮🇹 CIAO! 🤌
@antodippo
Shercode Holmes
Test coverage is a measure used to describe the degree to which the source code of a program is executed when a particular test suite runs
class NuclearReactor { public function isDangerous(int $temperature): bool { if ($temperature >= 1000) { return true; } return false; } }
class NuclearReactor { public function isDangerous(int $temperature): bool { if ($temperature >= 1000) { return true; } return false; } }
class NuclearReactor { public function isDangerous(int $temperature): bool { if ($temperature >= 1000) { return true; } return false; } }
class NuclearReactor { public function isDangerous(int $temperature): bool { if ($temperature >= 1000) { return true; } return false; } }
class NuclearReactor { public function isDangerous(int $temperature): bool { if ($temperature >= 1000) { return true; } return false; } }
class NuclearReactorTest extends TestCase { public function testIsDangerous(): void { $nuclearReactor = new NuclearReactor(); $this->assertFalse($nuclearReactor->isDangerous(500)); $this->assertTrue($nuclearReactor->isDangerous(2000)); } }
class NuclearReactorTest extends TestCase { public function testIsDangerous(): void { $nuclearReactor = new NuclearReactor(); $this->assertFalse($nuclearReactor->isDangerous(500)); $this->assertTrue($nuclearReactor->isDangerous(2000)); } }
class NuclearReactorTest extends TestCase { public function testIsDangerous(): void { $nuclearReactor = new NuclearReactor(); $this->assertFalse($nuclearReactor->isDangerous(500)); $this->assertTrue($nuclearReactor->isDangerous(2000)); } }
class NuclearReactorTest extends TestCase { public function testIsDangerous(): void { $nuclearReactor = new NuclearReactor(); $this->assertFalse($nuclearReactor->isDangerous(500)); $this->assertTrue($nuclearReactor->isDangerous(2000)); } }
from
"Tests Coverage is Dead" by Yotam Kadishay
class NuclearReactor { public function isDangerous(int $temperature): bool { if ($temperature > 1000) { return true; } return false; } }
class NuclearReactorTest extends TestCase { public function testIsDangerous(): void { $nuclearReactor = new NuclearReactor(); $this->assertFalse($nuclearReactor->isDangerous(500)); $this->assertTrue($nuclearReactor->isDangerous(2000)); } }
from
"Tests Coverage is Dead" by Yotam Kadishay
Cyclomatic complexity is a quantitative measure of the number of linearly independent paths through a program's source code
code is hard to understand
code is hard to test properly
code is hard to change
C.R.A.P.=comp(m)2·(1−cov(m)100)3+comp(m)
from "Pardon My French, But This Code Is C.R.A.P." by Alberto SavoiaNot all the units of code
are equally important
Churn is a metric representingfrom "Getting Empirical about Refactoring" by Michael Feathers
how often a unit of code is modified
(ex. number of commits)
Better, but it's still about coverage,
not the quality of the tests
Test doubles
vs
Mocking frameworks
vs
Mocks
class NuclearReactor
{
public function __construct(
private TemperatureSensor $sensor
) {}
public function isDangerous(): bool
{
if ($this->sensor->currentTemperature() >= 1000) {
return true;
}
return false;
}
}
class NuclearReactorTest extends TestCase
{
public function testIsDangerousWithMock(): void
{
$sensor = $this->createMock(TemperatureSensor::class);
$sensor->expects($this->once())
->method('currentTemperature')
->willReturn(2000);
$nuclearReactor = new NuclearReactor($sensor);
$this->assertTrue($nuclearReactor->isDangerous());
}
}
class NuclearReactorTest extends TestCase
{
public function testIsDangerousWithoutMocks(): void
{
$sensor = new FakeTemperatureSensor(2000);
$nuclearReactor = new NuclearReactor($sensor);
$this->assertTrue($nuclearReactor->isDangerous());
}
}
Cool, but let's find metrics!
Mutation testing
class NuclearReactor { public function isDangerous(int $temperature): bool { if ($temperature >= 1000) { return true; } return false; } }
class NuclearReactor { public function isDangerous(int $temperature): bool { if ($temperature >= 1000) { return true; } return false; } }
class NuclearReactor { public function isDangerous(int $temperature): bool { if ($temperature > 1000) { return true; } return false; } }
... is risky, so I won't do it
class NuclearReactorTest extends TestCase { public function testIsDangerous(): void { $nuclearReactor = new NuclearReactor(); $this->assertFalse($nuclearReactor->isDangerous(500)); $this->assertTrue($nuclearReactor->isDangerous(2000)); } }
https://github.com/antodippo/php-testing-playground
class NuclearReactorTest extends TestCase { public function testIsDangerous(): void { $nuclearReactor = new NuclearReactor(); $this->assertFalse($nuclearReactor->isDangerous(500)); $this->assertTrue($nuclearReactor->isDangerous(1000)); $this->assertTrue($nuclearReactor->isDangerous(2000)); } }
https://github.com/antodippo/php-testing-playground
PROS
|
CONS
|
To assess the effectiveness of a testsuite!
Setting a minimum MSI in pipeline
While developing a new feature, on a small scope
Ok, I have the tools, now what?
Feedback loops are! So...
release frequently
monitor
take educated risks!
learn from failures