Iniciando com testes
Vamos colocar todos na mesma página
1
Slide 4
Slide 4 text
Teste de software é o
processo de avaliar o correto
funcionamento de sistema
4
Slide 5
Slide 5 text
Por que devemos testar
nossos softwares?
5
Slide 6
Slide 6 text
Para garantir a segurança
6
Slide 7
Slide 7 text
Para garantir a qualidade
do produto
7
Slide 8
Slide 8 text
Deixar o cliente satisfeito
8
Slide 9
Slide 9 text
Porque é mais barato
9
Slide 10
Slide 10 text
Tipos de testes
Veremos as diferentes formas de testar nossos sistemas
2
Slide 11
Slide 11 text
11
Slide 12
Slide 12 text
Funcionais x Não funcionais
● Feitos geralmente por devs
● O foco é testar requisitos
funcionais
● Testa a conformidade dos
requisitos do cliente
12
● Podem ser feitos por
stakeholders
● Foco é testar requisitos não
funcionais
● Testa as expectativas do
cliente
Slide 13
Slide 13 text
Funcionais x Não funcionais
● Testes unitários
● Testes de integração
● Testes de sistema
● Testes de contrato
● Testes alpha/beta
13
● Testes de performance
○ Teste de carregamento
○ Teste de stress
● Testes de segurança
● Testes de usabilidade
Slide 14
Slide 14 text
Funcionais
14
Slide 15
Slide 15 text
Testes unitários
● Testa um componente de forma isolada
○ Classe
○ Método
○ Função
○ ..
15
Slide 16
Slide 16 text
16
public function testShouldBePalindrome
()
{
$checker = new Checker();
$isPalindrome = $checker->isPalindrome('arara')
$this->assertTrue($isPalindrome);
}
Slide 17
Slide 17 text
Testes de integração
● Testa como diferentes partes do sistema se comportam
○ Controllers
○ Models
○ DB
○ ...
17
Slide 18
Slide 18 text
18
public function testCreateUserByPOST() {
$response = $this->json('POST', '/users', ['name' => 'Juca']);
$this->assertStatus(201)
->assertJson([
'created' => true
]);
}
Slide 19
Slide 19 text
Testes de Sistema
● Testa como o comportamento do ponto de vista do usuário
○ Acessa uma página
○ Clica nos links
○ Preenche formulários
○ …
● Automatiza passos do usuário de uma forma programática
19
Slide 20
Slide 20 text
20
public function testBasicExample () {
$user = factory(User:: class)->create();
$this->browse(function ($browser) use ($user) {
$browser->visit( '/login')
->type( 'email', $user->email)
->type( 'password', 'password')
->press( 'Login')
->assertPathIs( '/home');
});
}
Slide 21
Slide 21 text
Testes de contrato
● Contrato é o que esperamos de outra parte
○ XML
○ JSON
○ ...
● Testes de contrato validam
○ respostas externas à nossa aplicação
○ Objetos disponíveis
21
Slide 22
Slide 22 text
22
Slide 23
Slide 23 text
23
Slide 24
Slide 24 text
Testes alpha e beta
● Consistem em criar um ambiente semelhante ao de prod
● Testa alpha
○ Equipe dev
○ Encontrar possíveis falhas
○ Ver como as funcionalidades se comportam
● Teste beta
○ Usuários
○ Feedbacks/Melhorias
24
Slide 25
Slide 25 text
Não Funcionais
25
Slide 26
Slide 26 text
Testes de carregamento
● Testa a velocidade de carregamento de uma página
○ Google Page Speed
26
Slide 27
Slide 27 text
27
Slide 28
Slide 28 text
Testes de stress
● Testa a capacidade da aplicação para responder a múltiplas
requisições
○ Neotys
○ ...
28
Slide 29
Slide 29 text
29
Slide 30
Slide 30 text
Testes de segurança
● Busca possíveis brechas na segurança que possam
comprometer os usuários
○ Arachni
○ ...
30
Slide 31
Slide 31 text
31
Slide 32
Slide 32 text
Aprofundando em TDD
Hora de conhecê-lo com mais intimidade
3
Slide 33
Slide 33 text
Kent Beck: um
pouco de
história
● Escreveu Sunit 1994
● Apresentou TDD na OOPSLA
1995
● Junto com Erich Gramma
publicou “Test Infected” (2000)
● TDD by Example
33
Slide 34
Slide 34 text
34
Slide 35
Slide 35 text
35
public function testShouldBePalindrome
()
{
$checker = new Checker();
$isPalindrome = $checker->isPalindrome('arara')
$this->assertTrue($isPalindrome);
}
Slide 36
Slide 36 text
36
class Checker {
public function isPalindrome(string $word) : bool
{
$originalWord = str_replace(' ', '', strtolower($word));
$reversed = str_replace(' ', '', strrev($originalWord));
return $originalWord == $reversed;
}
}
Slide 37
Slide 37 text
Detalhes
sobre TDD
Algumas curiosidades sobre a prática que
geralmente não entendemos de cara quando
começamos a estudar
37
Slide 38
Slide 38 text
“
38
TDD não é sobre testes e sim
sobre design
Slide 39
Slide 39 text
“
Nossos testes nos fornecem
feedbacks instantâneos sobre
nosso código
39
Slide 40
Slide 40 text
“
As suítes de testes não são tão
fiéis ao que estudamos na
literatura.
40
Slide 41
Slide 41 text
41
Slide 42
Slide 42 text
Conhecendo a família
xUnit
Agora que já entendemos um pouco de TDD, vamos falar sobre as suítes
de testes.
4
Slide 43
Slide 43 text
Gerard
Meszaros
● Estudou as estruturas das
principais suítes de testes
● Lançou xUnit Test Patterns
(2007)
43
Slide 44
Slide 44 text
As fases do xUnit
● Setup
○ Preparamos o ambiente para o teste
● Exercise
○ Simulamos o comportamento que esperamos testar
● Verify
○ Verificamos se ele teve o resultado esperado
● Teardown
○ Fazemos o ambiente voltar ao normal, como se o teste
nunca tivesse acontecido
44
Slide 45
Slide 45 text
45
public function testShouldBeInactivated
()
{
$this->user = User::create(
$this->data);
$this->user->setStatus(UserStatus::INACTIVE);
$this->assertFalse($this->user->isActive());
}
public function teardown()
{
$this->user->destroy();
}
Slide 46
Slide 46 text
46
public function testShouldBeInactivated
()
{
$this->user = User::create(
$this->data);
$this->user->setStatus(UserStatus::INACTIVE);
$this->assertFalse($this->user->isActive());
}
public function teardown()
{
$this->user->destroy();
}
Setup
Exercise
Verify
Teardown
Slide 47
Slide 47 text
SUT e colaboradores
● SUT (System Under Test)
○ O que está sendo testado em si
○ Classe, método, função, etc
● Colaboradores
○ Interagem com o SUT durante a execução do teste
47
Slide 48
Slide 48 text
48
public function testShouldSumItemsValueAtCart
()
{
$product = new Product(['value' => 20]);
$item = new Item(['quantity' => 2, 'product' => $product]);
$cart = new Cart();
$cart->addItem($item);
$this->assertEquals(40, $cart->totalValue());
}
Slide 49
Slide 49 text
49
public function testShouldSumItemsValueAtCart
()
{
$product = new Product(['value' => 20]);
$item = new Item(['quantity' => 2, 'product' => $product]);
$cart = new Cart();
$cart->addItem($item);
$this->assertEquals(40, $cart->totalValue());
}
Colaboradores
SUT
Slide 50
Slide 50 text
Colaboradores
● No exemplo anterior utilizamos as classes reais para testar
o SUT
● Podemos substituir esses colaboradores reais por dublês,
com isso, poderíamos chamar de Test Double
50
Slide 51
Slide 51 text
Test Doubles
5
Slide 52
Slide 52 text
Test Doubles
● Termo genérico para testes que substituem objetos de
produção por:
○ Dummy;
○ Fake;
○ Stub;
○ Spy;
○ Mock;
52
Slide 53
Slide 53 text
Dummy
● São utilizados para preencher listas de parâmetros, porém,
não são utilizados
● Existem dois tipos:
○ Dummy Object
○ Dummy Value
53
Slide 54
Slide 54 text
54
public function depositMoney(float value, Account $account)
{
if ($value <= 0) {
throw new \InvalidArgumentException();
}
$account->subtractCurrentBalance(
$value);
}
Slide 55
Slide 55 text
55
/**
* @expectedException InvalidArgumentException
* */
public function testWhenValueLessOrEqualZeroShouldThrowAnException
()
{
$account = $this->prophesize(Account::class);
$deposit = new Deposit();
$deposit->depositMoney(-10, $account->reveal();
}
Slide 56
Slide 56 text
Fake
● Substituem objetos para criar atalhos ou formas mais fáceis
de executar algo
● Exemplo: InMemoryTestDatabase
56
Slide 57
Slide 57 text
57
class ClientRepositoryFake {
private $clients = [];
public function save(Client $client) : Client {
$id = count($this->clients);
$client->setId($id);
$this->clients[$id] = $client;
return $client;
}
public function find(int $id) : Client {
return $this->clients[$id];
}
public function update(Client $client) : Client {
$this->clients[$client->getId()] = $client;
return $client;
}
}
Slide 58
Slide 58 text
58
public function setup()
{
$client = new Client(['name' => 'Gandalf', 'cpf' => '87511196098']);
$this->clientRepository = new ClientRepositoryFake();
$this->clientRepository->save($user);
}
public function testAssociateShouldGenerateAccountNumber()
{
$client = $this->clientRepository->find(1);
$account = new Account();
$account->setClient($client);
$accountAssociator = AccountAssociator();
$accountAssociator->associateAccountToClient($account, $client);
$this->assertNotNull($account->getNumber());
}
Slide 59
Slide 59 text
Stub
● Fornece respostas prontas programadas para chamadas
específicas em momento de execução
● São utilizados na fase do setup
59
Slide 60
Slide 60 text
60
public function create()
{
if (!$this->validator->isCPFValid(
$this->data['cpf'])
{
throw new \Exception('Invalid CPF');
}
return $this->repository->create();
}
Slide 61
Slide 61 text
61
public function testShouldCreateAccountWhenCPFIsValid
()
{
$validator = $this->prophesize(Validator::class);
$validator->isCPFValid('23430222915')->willReturn(true);
$data = ['cpf' => '23430222915'];
$account = new Account($data);
$account->setValidator($validator->reveal());
$this->instanceOf(Account::class, $account->create());
}
Slide 62
Slide 62 text
Spy
● Possue controle sobre as chamadas que são feitas em
tempo de execução
● Se foco é saber se determinado método/função foi
chamado e como foi
62
Slide 63
Slide 63 text
63
class AddressReposity
{
public function save(Address $address)
{
$this->entityManager->persist($address);
$this->entityManager->flush();
}
}
Slide 64
Slide 64 text
64
public function shouldSaveNewAddress()
{
$em = $prophet->prophesize('Doctrine\ORM\EntityManager'
);
$address = new Address();
$addressRepository = new AddressRepository($em->reveal());
$addressRepository->save($address);
$em->flush()->shouldHaveBeenCalled();
}
Slide 65
Slide 65 text
Mock
● São utilizados na fase do verify
● Diferente dos demais, é o único que faz a verificação por
comportamento e não por estado
65
Slide 66
Slide 66 text
66
public function create()
{
if (!$this->validator->isCPFValid(
$this->data['cpf'])
{
throw new \Exception('Invalid CPF');
}
return $this->repository->create();
}
Slide 67
Slide 67 text
public function testShouldCreateAccountWhenCPFIsValid()
{
$validator = $this->prophesize(Validator::class);
$validator->isCPFValid('23430222915')
->willReturn(true)
->shouldBeCalled($this->once());
$repository = $this->prophesize(Repository::class);
$repository->create()->shouldBeCalled($this->once());
$data = ['cpf' => '23430222915'];
$account = new Account($data);
$account->setValidator($validator->reveal());
$account->setRepository($repository->reveal());
$account->create();
}
Slide 68
Slide 68 text
BDD e TDD
Essa duas siglas podem parecer mesma coisa, porém não são
5
Slide 69
Slide 69 text
BDD
● Behaviour Driven Development
● É uma metodologia na qual todos os stakeholders são
envolvidos
● Começa com especificações do cliente e termina no
projeto entregue
69
72
BDD x TDD
● Começa descrevendo
features e scenarios
● Envolve vários stakeholders
● Foco no comportamento
final
● Começa escrevendo casos
de teste
● Envolve apenas devs
● Foco na implementação
Slide 73
Slide 73 text
Abordagens
Dicas de abordagens para testes
5
Slide 74
Slide 74 text
Projetos legados
● De dentro para fora
● Testar apenas código modificado
● Testar apenas os requisitos
● Adicionar apenas código testado
● Quebrar dependências escondidas
74