🇮🇹 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 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
\begin{align} C.R.A.P. &= comp(m)^2 · (1 - \frac{cov(m)}{100})^3 + comp(m) \end{align}
from "Pardon My French, But This Code Is C.R.A.P." by Alberto SavoiaNot all the units of codeare equally important
Churn is a metric representinghow often a unit of code is modified (ex. number of commits)from "Getting Empirical about Refactoring" by Michael Feathers
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;
}
}
... 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