Slide 1

Slide 1 text

Testes além do TDD

Slide 2

Slide 2 text

Olá! Vinícius Alonso Desenvolvedor 2

Slide 3

Slide 3 text

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

Slide 70

Slide 70 text

70

Slide 71

Slide 71 text

71 BDD ● Feature: … ○ Scenario: … ■ When: … ■ And: … ■ Then: … ● Especificações executáveis

Slide 72

Slide 72 text

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

Slide 75

Slide 75 text

Novos projetos ● Boa arquitetura ● Modular ● Testar comportamentos 75

Slide 76

Slide 76 text

Regras complexas ● Especificações executáveis para documentar 76

Slide 77

Slide 77 text

API’s externas ● Stubs para as chamadas ● Testes de contrato 77

Slide 78

Slide 78 text

Conclusões 78

Slide 79

Slide 79 text

Testar um software vai muito além de escrever testes 79

Slide 80

Slide 80 text

Arquiteturas ruins impedem testes de serem escritos 80

Slide 81

Slide 81 text

Qual é a estratégia de testes ideal para o seu projeto? 81

Slide 82

Slide 82 text

82 Obrigado! Dúvidas?

Slide 83

Slide 83 text

Referências ● https:/ /martinfowler.com/bliki/InMemoryTestDatabase.ht ml ● https:/ /martinfowler.com/bliki/TestDouble.html ● https:/ /martinfowler.com/articles/mocksArentStubs.html ● https:/ /www.amazon.com.br/Xunit-Test-Patterns-Refacto ring-Code/dp/0131495054 ● https://www.softwaretestinghelp.com/functional-testing-vs-no n-functional-testing/ 83

Slide 84

Slide 84 text

Referências ● https://docs.pact.io/ ● https://martinfowler.com/bliki/ContractTest.html ● https://martinfowler.com/articles/practical-test-pyramid.html ● https://medium.com/edureka/types-of-software-testing-d7aa2 9090b5b ● https://hackr.io/blog/top-10-open-source-security-testing-tools -for-web-applications ● https://danlimerick.wordpress.com/2012/04/25/tdd-when-up-t o-your-neck-in-legacy-code/ 84

Slide 85

Slide 85 text

Referências ● https://codingsight.com/rules-for-implementing-tdd-in-old-proj ect/ ● http://shipit.resultadosdigitais.com.br/blog/bem-vindo-ao-mar avilhoso-mundo-dos-testes-de-contrato/ 85