Testes de unidade na prática
Porquê?Quando?Como?
Tiago Furtado <tfurtado@gmail.com>
Full-stack developer, Meritt
XVII SECCOM
Tiago Furtado
Mestre em Ciência da Computação
Universidade Federal de Viçosa (UFV)
Vamos falar de coisa boa?
Testes de unidade
Testes de softwareunidade
Testes de software
8/70
Testes de software
9/70
Testes de software
Martin Fowler. martinfowler.com/bliki/TestPyramid.html, 2012.
10/70
Testes de software
11/70
Testes de unidade
O que são? Onde vivem? De que se alimentam?
Testes de unidade
interfaceCalculatorInterface{
publicfunctionsum($first,$second);
publicfunctionsubtract($first,$second);
}
classCalculatorimplementsCalculatorInterface{/*...*/}
classCalculatorTest{
/**@test*/
publicfunctionsumShouldReturnTheSumOfTwoNumbers(){
$calculator=newCalculator();
$result=$calculator->sum(1,2);
if($result!==3){
thrownewException("Somethingwrong'snotright¯_(ツ)_/¯");
}
}
}
PHP
13/70
Testes de unidade
Por quê?
Software livre de defeitos deveria ser sempre entregue
Mas...
·
·
software é muito complexo
pessoas são imperfeitas! ><"
-
-
14/70
O todo é maior do que a simples soma
das suas partes.
“
”
Aristóteles
Testes de unidade
Por quê?
Garantir a correção das partes
interfacePersonInterface{
publicfunctioncanBeArrested();
}
classPersonimplementsPersonInterface{
publicfunction__construct($age);
/*...*/
}
(newPerson(17))->canBeArrested();
(newPerson(18))->canBeArrested();
(newPerson(19))->canBeArrested();
(newPerson(-1))->canBeArrested();
(newPerson(0))->canBeArrested();
(newPerson("RUKM?"))->canBeArrested();
PHP
Testes de unidade
Por quê?
Ampliar a capacidade de análise do todo
interfacePersonInterface{/*...*/}
classPersonimplementsPersonInterface{
publicfunction__construct($age);
/*...*/
}
interfacePoliceInterface{
publicfunctionarrest(PersonInterface$person);
}
classPoliceimplementsPoliceInterface{/*...*/}
$police=newPolice();
$police->arrest(newPerson(15));
$police->arrest(newPerson(19));
PHP
Testes de unidade
Como?
Manualmente
functionsum($a,$b){
return$a+0;
}
printf("sum(%d,%d)=%d[%d]n",0,0,sum(0,0),0);
printf("sum(%d,%d)=%d[%d]n",1,0,sum(1,0),1);
printf("sum(%d,%d)=%d[%d]n",0,1,sum(0,1),1);
PHP
sum(0,0)=0[0]
sum(1,0)=1[1]
sum(0,1)=0[1]
18/70
Testes de unidade
Como?
Manualmente
functionsum($a,$b){
return$a+$b;
}
printf("sum(%d,%d)=%d[%d]n",0,0,sum(0,0),0);
printf("sum(%d,%d)=%d[%d]n",1,0,sum(1,0),1);
printf("sum(%d,%d)=%d[%d]n",0,1,sum(0,1),1);
PHP
sum(0,0)=0[0]
sum(1,0)=1[1]
sum(0,1)=1[1]
19/70
Testes de unidade
1 <?php
2 functionsum($a,$b){
3 return0+$b;
4 }
5
6 functionsumTest($a,$b,$c){
7 if(sum($a,$b)===$c){return;}
8 thrownewException(/*...*/);
9 }
10sumTest(0,0,0);
11sumTest(1,0,1);
12sumTest(0,1,1);
PHP
PHPFatalerror: Uncaughtexception'Exception'insumTest.php:8
Stacktrace:
#0sumTest.php(11):sumTest(1,0,1)
#1{main}
throwninsumTest.phponline8
Testes de unidade
Como?
Usando um framework de testes
classCalculator{
publicfunctionsum($a,$b){
return$a+$b;
}
}
classCalculatorTestextendsPHPUnit_Framework_TestCase{
/**@test*/
publicfunctionsumTest(){
$this->assertSame(0,sum(0,0));
$this->assertSame(1,sum(1,0));
$this->assertSame(1,sum(0,1));
}
}
PHP
Testes de unidade
Como?
Manualmente
23/70
Testes de unidade
Como?
~Automático~
24/70
Testes de unidade
Como?
Usando um framework de testes
25/70
E quando um objeto interage com outro?
26/70
Objetos dublês!
27/70
Testes de unidade
classPoliceimplementsPoliceInterface{
publicfunctionarrest(PersonInterface$person){
if(!$person->canBeArrested()){
thrownewException(/*...*/);
}
}
}
PHP
28/70
Testes de unidade
classPoliceTestextendsPHPUnit_Framework_TestCase{
/**@test*/
publicfunctionarrestShouldThrowExceptionIfPersonCantBeArrested(){
$person=$this->getMockForAbstractClass(PersonInterface::class);
$person->expects($this->once())
->method('canBeArrested')
->willReturn(false);
$this->setExpectedException(Exception::class);
$police=newPolice();
$police->arrest($person);
}
}
PHP
29/70
Quando escrevê-los?!
30/70
TDD
Test-driven development
Test-driven development (TDD)
Princípios
KISS: Keep It Simple, Stupid
YAGNI: You Aren't Gonna Need It
33/70
Test-driven development (TDD)
34/70
Test-driven development (TDD)
1. Escrever um teste
classCalculatorTestextendsPHPUnit_Framework_TestCase
{
/**
*@test
*/
publicfunctionsumTest()
{
}
}
PHP
35/70
Test-driven development (TDD)
2. Garantir que o novo teste falha
$./vendor/bin/phpunit--bootstrap./vendor/autoload.php
test/CalculatorTest.php
PHPUnit4.5-gf75e6b2bySebastianBergmann.
.
Time:75ms,Memory:2.75Mb
OK(1test,0assertions)
36/70
Test-driven development (TDD)
2. Garantir que o novo teste falha
classCalculatorTestextendsPHPUnit_Framework_TestCase
{
/**
*@test
*/
publicfunctionsumTest()
{
$calculator=newCalculator();
}
}
PHP
37/70
Test-driven development (TDD)
2. Garantir que o novo teste falha
$./vendor/bin/phpunit--bootstrap./vendor/autoload.php
test/CalculatorTest.php
PHPUnit4.5-gf75e6b2bySebastianBergmann.
PHPFatalerror:
Class'TFurtadoUnitTestSampleCalculator'notfound
in.../test/CalculatorTest.phponline19
PHPStacktrace:
PHP 1.{main}()./vendor/phpunit/phpunit/phpunit:0
...
38/70
Test-driven development (TDD)
3. Escrever código
classCalculator
{
}
PHP
40/70
Test-driven development (TDD)
4. Garantir que os testes passam
$./vendor/bin/phpunit--bootstrap./vendor/autoload.php
test/CalculatorTest.php
PHPUnit4.5-gf75e6b2bySebastianBergmann.
.
Time:65ms,Memory:2.75Mb
OK(1test,0assertions)
41/70
Test-driven development (TDD)
5. Refatorar o código
42/70
Test-driven development (TDD)
Repetir...
43/70
Test-driven development (TDD)
1. Escrever um teste
classCalculatorTestextendsPHPUnit_Framework_TestCase
{
/**
*@test
*/
publicfunctionsumTest()
{
$calculator=newCalculator();
$this->assertSame(3,$calculator->sum(1,2));
}
}
PHP
44/70
Test-driven development (TDD)
2. Garantir que o novo teste falha
$./vendor/bin/phpunit--bootstrap./vendor/autoload.php
test/CalculatorTest.php
PHPUnit4.5-gf75e6b2bySebastianBergmann.
PHPFatalerror: Calltoundefinedmethod
TFurtadoUnitTestSampleCalculator::sum()
in.../test/CalculatorTest.phponline20
PHPStacktrace:
PHP 1.{main}()./vendor/phpunit/phpunit/phpunit:0
...
45/70
Test-driven development (TDD)
3. Escrever código
classCalculator
{
publicfunctionsum($a,$b)
{
$sum=3;
return$sum;
}
}
PHP
46/70
Test-driven development (TDD)
4. Garantir que os testes passam
$./vendor/bin/phpunit--bootstrap./vendor/autoload.php
test/CalculatorTest.php
PHPUnit4.5-gf75e6b2bySebastianBergmann.
.
Time:77ms,Memory:2.75Mb
OK(1test,1assertion)
47/70
Test-driven development (TDD)
5. Refatorar o código
classCalculator
{
publicfunctionsum($a,$b)
{
return3;
}
}
$sum=3;
return$sum;
PHP
48/70
Test-driven development (TDD)
5. Refatorar o código
$./vendor/bin/phpunit--bootstrap./vendor/autoload.php
test/CalculatorTest.php
PHPUnit4.5-gf75e6b2bySebastianBergmann.
.
Time:87ms,Memory:2.75Mb
OK(1test,1assertion)
49/70
Test-driven development (TDD)
Repetir...
50/70
Test-driven development (TDD)
1. Escrever um teste
classCalculatorTestextendsPHPUnit_Framework_TestCase
{
/**
*@test
*/
publicfunctionsumTest()
{
$calculator=newCalculator();
$this->assertSame(3,$calculator->sum(1,2));
$this->assertSame(4,$calculator->sum(2,2));
}
}
PHP
51/70
Test-driven development (TDD)
2. Garantir que o novo teste falha
$./vendor/bin/phpunit--bootstrap./vendor/autoload.php
test/CalculatorTest.php
PHPUnit4.5-gf75e6b2bySebastianBergmann.
F
Time:76ms,Memory:3.00Mb
Therewas1failure:
1)TFurtadoUnitTestSampleCalculatorTest::sumTest
Failedassertingthat3isidenticalto4.
.../test/CalculatorTest.php:21
FAILURES!
Tests:1,Assertions:2,Failures:1.
52/70
Test-driven development (TDD)
3. Escrever código
classCalculator
{
publicfunctionsum($a,$b)
{
$sum=$a+$b;
return$sum;
}
}
return3;
PHP
53/70
Test-driven development (TDD)
4. Garantir que os testes passam
$./vendor/bin/phpunit--bootstrap./vendor/autoload.php
test/CalculatorTest.php
PHPUnit4.5-gf75e6b2bySebastianBergmann.
.
Time:90ms,Memory:2.75Mb
OK(1test,2assertions)
54/70
Test-driven development (TDD)
5. Refatorar o código
classCalculator
{
publicfunctionsum($a,$b)
{
;
return$a+$b;
}
}
$sum=$a+$b;
return$sum
PHP
55/70
Test-driven development (TDD)
5. Refatorar o código
$./vendor/bin/phpunit--bootstrap./vendor/autoload.php
test/CalculatorTest.php
PHPUnit4.5-gf75e6b2bySebastianBergmann.
.
Time:87ms,Memory:2.75Mb
OK(1test,1assertion)
56/70
Test-driven development (TDD)
Repetir...
57/70
Cobertura de testes
Quanto do software deve estar coberto por
testes de unidade?
100%!
TODO!
O software INTEIRO!
Deu pra endenter, né?
59/70
Como garantir 100% de cobertura de testes?
60/70
Testes de unidade na Meritt
Testes de unidade na Meritt
Status
63/70
Testes de unidade na Meritt
Status
64/70
Considerações finais
Considerações finais
Testes de unidade são...
... essenciais para garantir a manutenibilidade do software
... instrumentos de simples implementação
... muito valiosos para criar um produto de qualidade
... uma importante forma de documentação técnica
... divertidos! Por que não?
·
·
·
·
·
66/70
Considerações finais
Testes de unidade não são...
... a abordagem definitiva para testes de software
... uma garantia de qualidade do produto final
... a solução mágica para software mal arquitetado
·
·
·
67/70
Temos vagas!
meritt.recruiterbox.com
Pay attention to zeros. If there is a zero,
someone will divide by it.
“
”
Cem Kaner
Muito obrigado!
tfurtado@gmail.com
speakerdeck.com/tfurtado
github.com/tfurtado
meritt.com.br

Testes de unidade na prática