@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
\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
Mocks
vs
Mocking frameworks
vs
Test doubles
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());
}
}
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?
Release frequently
Monitor
Take educated risks!
Learn from failures