Slide 1

Slide 1 text

Marcel Gonçalves dos Santos @marcelgsantos dublês de testes desmistificando os

Slide 2

Slide 2 text

pensandonaweb.com.br desenvolvedor web full-stack Marcel Gonçalves dos Santos @marcelgsantos

Slide 3

Slide 3 text

@phpsp phpsp.org.br

Slide 4

Slide 4 text

Interaja nas mídias sociais! 
 
 - fale sobre o evento, palestrantes e conteúdo - tire fotos do evento e publique 
 - interaja com outros participantes do evento - tire dúvidas ou dê feedbacks para os palestrantes

Slide 5

Slide 5 text

1. seguir @marcelgsantos no Twitter 
 2. tuitar utilizando as hashtags #testes e #TheDevConf e me marcar no tweet 
 3. não vale tuíte em branco 
 4. não vale retuíte Concorra a um livro da Casa do Código! 🤩

Slide 6

Slide 6 text

Introdução

Slide 7

Slide 7 text

é senso comum que testes automatizados são fundamentais para a construção de um software robusto

Slide 8

Slide 8 text

sempre que nos deparamos com conteúdos sobre testes imaginamos que a prática será fácil de ser aplicada em um projeto real

Slide 9

Slide 9 text

basta "apenas" preparar o cenário de teste, executar o que queremos testar e comparar o resultado com o esperado, não é mesmo?

Slide 10

Slide 10 text

class Calculator { public function sum(float $a, float $b) : float { return $a + $b; } / / other implementations . . . }

Slide 11

Slide 11 text

mas, na prática, testar uma aplicação é um pouco mais complicado do que parece!

Slide 12

Slide 12 text

o objetivo dessa palestra é facilitar a compreensão de diversos conceitos sobre testes

Slide 13

Slide 13 text

Princípios de Design

Slide 14

Slide 14 text

coesão indica o grau de relação entre os membros de um módulo

Slide 15

Slide 15 text

/ / not cohesive class 
 class Cart { private $items; public function _ _ construct() { $this - > items = []; } public function numberOfItems() : int { return count($this - > items); } public function calculateDeliveryPrice() : float { / / calculates the delivery price } }

Slide 16

Slide 16 text

acoplamento indica o grau de dependência entre classes

Slide 17

Slide 17 text

o acoplamento ocorre quando o código de um módulo utiliza código…

Slide 18

Slide 18 text

…de outro módulo, seja ao chamar uma função ou acessar algum dado

Slide 19

Slide 19 text

/ / class Car is coupled to Engine class 
 class Car { private $engine; public function _ _ construct() { $this - > engine = new Engine(); } public function start() { $this - > engine - > start(); / / engine is a dependency } } 
 
 $car = new Car(); $car - > start(); / / Starting the engine

Slide 20

Slide 20 text

o acoplamento é algo desejado, porém, que deve ser controlado

Slide 21

Slide 21 text

ao controlar o acoplamento o software torna-se mais fl exível e fácil de manter

Slide 22

Slide 22 text

pode-se reduzir o acoplamento através da injeção de dependências, isto é, fornecer uma dependência do mundo externo para uma classe

Slide 23

Slide 23 text

/ / dependency injection via constructor 
 class Car { private $engine; public function _ _ construct(Engine $engine) { $this - > engine = $engine; } public function start() { $this - > engine - > start(); } }

Slide 24

Slide 24 text

/ / inject an engine dependency into the car 
 $engine = new Engine(); $car = new Car($engine); $car - > start(); / / Starting the engine

Slide 25

Slide 25 text

Testes

Slide 26

Slide 26 text

ao testar código é comum reduzir o escopo de teste para algo mais especí fi co, isto é, uma classe, módulo ou método

Slide 27

Slide 27 text

o código que é alvo de teste é chamado de system under test (SUT)

Slide 28

Slide 28 text

esse código, normalmente, possui dependências que são passadas via construtor

Slide 29

Slide 29 text

class CreateUser { private UserRepository $userRepository; private Notif i cationService $notif i cationService; public function _ _ construct( UserRepository $userRepository, Notif i cationService $notif i cationService ) { $this - > userRepository = $userRepository; $this - > notif i cationService = $notif i cationService; } public function execute(array $data) : void { / / orchestrates the domain to create a user . . . } } a classe CreateUser é o system under test (SUT)

Slide 30

Slide 30 text

uma dependência é chamada de depended- on-component (DOC) ou colaborador

Slide 31

Slide 31 text

class CreateUser { private UserRepository $userRepository; private Notif i cationService $notif i cationService; public function _ _ construct( UserRepository $userRepository, Notif i cationService $notif i cationService ) { $this - > userRepository = $userRepository; $this - > notif i cationService = $notif i cationService; } public function execute(array $data) : void { / / orchestrates the domain to create a user . . . } } UserRepository e NotificationService são colaboradores (DOC), isto é, poderão ser substituídos por dublês de testes

Slide 32

Slide 32 text

saber identi fi car o papel de cada elemento do código no contexto do teste ajuda numa melhor compreensão dos conceitos

Slide 33

Slide 33 text

Dublês de Testes

Slide 34

Slide 34 text

os dublês de teste são substitutos que sobrepõem dependências necessárias para se testar um sistema ou um comportamento

Slide 35

Slide 35 text

os dublês de teste são melhor aplicados quando substituem dependências lentas, não-determinísticas ou de difícil con fi guração

Slide 36

Slide 36 text

são exemplos de dependências lentas as chamadas para APIs e não-determinísticas um serviço que obtém datas ou gera números aleatórios

Slide 37

Slide 37 text

o conceito de dublês de teste foi criado por Gerard Meszaros no livro xUnit Test patterns: Refactoring Test Code

Slide 38

Slide 38 text

os dublês de teste mais conhecidos são: dummy, stub, spy, fake e mock

Slide 39

Slide 39 text

o conceito de dublês de teste é simples 
 mas a quantidade de nomenclaturas e ferramentas acabam causando confusão

Slide 40

Slide 40 text

As Fases de Teste 
 do Padrão xUnit

Slide 41

Slide 41 text

as quatro fases de teste são: 
 
 setup - coloca o sistema no estado necessário 
 exercise - interage com o objeto sob teste 
 verify - veri fi ca se o comportamento aconteceu 
 teardown - colocar o sistema no estado anterior ao teste

Slide 42

Slide 42 text

Dummy

Slide 43

Slide 43 text

um dummy é utilizado para preencher parâmetros obrigatórios

Slide 44

Slide 44 text

eles podem ser criados manualmente, isto é, sem a necessidade de ferramentas externas

Slide 45

Slide 45 text

eles são os dublês de testes mais simples que existem

Slide 46

Slide 46 text

public function testRemoveAnInexistentItemShouldThrowAnException() : void { $product = new Product(1, 'hamburguer', 20); $item = new Item($product, 2, 0); $shoppingCart = new ShoppingCart(); $this - > expectException(ShoppingCartException : : class); $shoppingCart - > removeItem($item); } o objeto item é um dummy pois, apesar da necessidade de passá-lo como parâmetro, ele não é utilizado na lógica que lança a exceção

Slide 47

Slide 47 text

ao ser passado como dependência ou parâ- metro um dummy pode não ser utilizado

Slide 48

Slide 48 text

Stub

Slide 49

Slide 49 text

um stub é utilizado para fornecer respostas fi xas ou pré-con fi guradas para substituir a implementação real de uma dependência

Slide 50

Slide 50 text

eles podem ser criados manualmente ou utilizando ferramentas externas

Slide 51

Slide 51 text

eles evitam que chamadas lentas ou não- determinísticas sejam feitas durante a execução do teste

Slide 52

Slide 52 text

public function testCreateUserWithExistentEmailShouldNotWork() : void { $existentEmail = '[email protected]'; $payload = $this - > validPayload(); $userRepositoryMock = $this - > createMock(UserRepository : : class); $notif i cationServiceMock = $this - > createMock(Notif i cationService : : class); $createUser = new UserCreator($userRepositoryMock, $notif i cationServiceMock); $userRepositoryMock - > method('f i ndIfEmailIsUsedByUser') - > with($existentEmail) - > willReturn(true); $this - > expectException(InvalidUserException : : class); $this - > expectExceptionMessage("O e - mail $existentEmail já está sendo utilizado."); $createUser - > execute($payload); } cria uma resposta pré-configurada para colocar o código no estado esperado para a realização do teste apesar de utilizar o método createMock, o dublê de teste trata-se de um stub

Slide 53

Slide 53 text

deve-se utilizar stubs quando precisar de respostas rápidas, determinísticas e pré- con fi guradas para o seu teste

Slide 54

Slide 54 text

um stub é um dublê de teste utilizado na fase de setup

Slide 55

Slide 55 text

Fake

Slide 56

Slide 56 text

um fake é utilizado para fornecer respostas fi xas ou pré-con fi guradas, assim como um stub, com a diferença que ele utiliza uma implementação funcional

Slide 57

Slide 57 text

um fake não precisa conhecer a implementação concreta de quem ele substitui, isto é, não ocorre vazamento de detalhes internos das dependências

Slide 58

Slide 58 text

ele pode ser utilizado para reproduzir respostas mais complexas que não seria possível utilizando stubs

Slide 59

Slide 59 text

os fakes são bastante utilizados em testes que estão na fronteira de I/O do sistema como, por exemplo, banco de dados

Slide 60

Slide 60 text

class MemoryCustomerRepository implements CustomerRepository { private array $customers; public function persist(Customer $customer) : void { $this - > customers[$customer - > id()] = $customer; } public function f i ndById(CustomerId $customerId) : Customer { return $this - > customers[$customerId]; } public function f i ndByBirthday(DateTimeImmutable $currentDate) : array { return array_f i lter( $this - > customers, fn(Customer $customer) = > $customer - > isBirthday($currentDate) ); } } um fake, diferentemente de um stub, possui uma implementação funcional

Slide 61

Slide 61 text

Mock

Slide 62

Slide 62 text

um mock é utilizado para veri fi car interações entre o código testado (SUT) 
 e suas dependências (DOC)

Slide 63

Slide 63 text

os objetos se comunicam através de troca de mensagens, isto é, chamadas de métodos

Slide 64

Slide 64 text

um mock é utilizado para garantir que a mensagem foi enviada

Slide 65

Slide 65 text

utiliza-se mocks quando o comportamento a ser testado não retorna nenhum valor como, por exemplo, o envio de um e-mail

Slide 66

Slide 66 text

public function testCreateUserWithValidDataShouldWork() : void { $payload = $this - > validPayload(); $userRepositoryMock = $this - > createMock(UserRepository : : class); $notif i cationServiceMock = $this - > createMock(Notif i cationService : : class); $createUser = new UserCreator($userRepositoryMock, $notif i cationServiceMock); $userRepositoryMock - > expects($this - > once()) - > method('persist'); $notif i cationServiceMock - > expects($this - > once()) - > method('sendConf i rmation'); $createUser - > execute($payload); } o mock garante que o método de uma dependência foi chamado, isto é, que a mensagem foi enviada para o outro objeto a fase de verify é feita antes da fase de exercise quando utilizamos mock

Slide 67

Slide 67 text

podemos dizer que o mock faz a veri fi cação por comportamento e os outros dublês de testes fazem a veri fi cação por estado

Slide 68

Slide 68 text

um mock é um dublê de teste utilizado na fase de verify

Slide 69

Slide 69 text

o termo "mockar um objeto" refere-se a programá-lo para veri fi car se ele recebeu a mensagem e não programá-lo para retornar um valor padrão

Slide 70

Slide 70 text

quando mockar um objeto? - quando um objeto é difícil de ser instanciado - quando um objeto causa efeitos no mundo exterior (enviar e-mail) - quando quero veri fi car e garantir o comportamento de um colaborador

Slide 71

Slide 71 text

todos os dublês de testes, por questões de simplicidade, são comumente chamados de mock

Slide 72

Slide 72 text

isso se deve pois o termo é generalizado pela maioria das ferramentas que criam dublês de teste

Slide 73

Slide 73 text

os mocks surgiram como uma ferramenta 
 de design para descobrir a API dos colabo- radores do ponto de vista de quem vai consumi-las

Slide 74

Slide 74 text

essa abordagem é conhecida como modo outside-in

Slide 75

Slide 75 text

Spy

Slide 76

Slide 76 text

um spy é utilizado para veri fi car interações entre o código testado (SUT) e suas depen- dências (DOC), porém, utiliza uma imple- mentação funcional para operar

Slide 77

Slide 77 text

os spies são dublês de testes que registram como eles são utilizados de forma que con- seguimos perguntá-los sobre a execução e fazer asserções

Slide 78

Slide 78 text

eles podem ser utilizados como uma alternativa ao uso de mocks

Slide 79

Slide 79 text

Categorias

Slide 80

Slide 80 text

os dublês de testes podem ser categorizados de inúmeras formas

Slide 81

Slide 81 text

um dublê de teste pode simular comportamento ou observar interações

Slide 82

Slide 82 text

um dublê de teste pode também ter ou não uma implementação funcional

Slide 83

Slide 83 text

dummy - não simula comportamento e não observa interação - não possui implementação funcional

Slide 84

Slide 84 text

stub - simula comportamento - não possui implementação funcional

Slide 85

Slide 85 text

fake - simula comportamento - possui implementação funcional

Slide 86

Slide 86 text

mock - observa interação - não possui implementação funcional

Slide 87

Slide 87 text

spy - observa interação - possui implementação funcional

Slide 88

Slide 88 text

Conclusão

Slide 89

Slide 89 text

os testes automatizados são fundamentais para a construção de um software robusto, ajuda na qualidade interna do código…

Slide 90

Slide 90 text

…e permite que o software tenha uma evolução sustentável

Slide 91

Slide 91 text

para facilitar a construção de testes recomenda-se seguir boas práticas de design de código como ter um código com alta coesão e baixo acoplamento

Slide 92

Slide 92 text

o baixo acoplamento e a injeção de depen- dência permite a substituição de dependên- cias reais por dependências simuladas

Slide 93

Slide 93 text

essas dependências simuladas são chama- das de dublês de testes e permitem criar testes rápidos, determinísticos e de fácil con fi guração

Slide 94

Slide 94 text

existem vários dublês de testes cada um com suas características e usos

Slide 95

Slide 95 text

a maioria das pessoas se referem aos dublês de testes como mocks mas, como dito, existem diversos dublês diferentes

Slide 96

Slide 96 text

vá em frente, estude e divirta-se! ;)

Slide 97

Slide 97 text

Referências

Slide 98

Slide 98 text

bit.ly/palestra-dubles-de-testes

Slide 99

Slide 99 text

Avalie!

Slide 100

Slide 100 text

@marcelgsantos speakerdeck.com/marcelgsantos Obrigado. Perguntas?