Skip to content

Instantly share code, notes, and snippets.

@marcelgsantos
Last active February 10, 2022 14:12
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save marcelgsantos/c82a67fe6250ca4070b2118b9d4753de to your computer and use it in GitHub Desktop.
Save marcelgsantos/c82a67fe6250ca4070b2118b9d4753de to your computer and use it in GitHub Desktop.
  • Por que fazer testes?
    • saber se o software está funcionando de maneira automatizada
      • não elimina os testes exploratórios feito de forma manual
    • manter custos de desenvolvimento em níveis saudáveis
    • ajuda na qualidade interna do código (design e arquitetura do código)
  • Como avaliar a qualidade dos testes (se estão bem feitos)?
    • corretude - se o teste não está gerando um falso positivo
    • adequação do tipo de teste - se o teste é o mais adequado para a situação
    • clareza - se o teste é fácil de ler
  • adequação do tipo de teste
    • qual o tipo de teste escrever?
      • aceitação - testa o requisito funcional (o que o usuario vê e o que está especificado nos requisitos funcionais)
      • unitário - testa uma unidade do sistema (classe ou método)
      • integração - testa um comportamento que dois ou mais objetos fazem juntos
  • O teste de aceitação testa a regra de negócio e não a interface (botão ou texto na tela)
  • Recomenda-se escrever o código em termos do domínio do problema e não do domínio técnico
  • A pirâmide de testes é um guia sobre quantos testes devem ser escritos proporcionalmente entre testes de aceitação, integração e unitário.
  • Na pirâmide de testes quanto mais perto do topo, o teste é mais frágil, mais lento e possui mais garantia de qualidade externa. Ao passo que quanto mais perto da base, o teste é menos frágil, mais rápido e possui menos garantia de qualidade externa.
  • Pode-se utilizar teste unitário para realizar testes de views para verificar se um botão está pressionado como padrão, por exemplo, ao invés de se utilizar testes de aceitação.
  • clareza
    • é importante para o desenvolvedor (facilitar a leitura)
    • é importante consirando o teste como documentação (linha de pensamento de BDD)
    • Um teste pode ser estruturado (assim como uma redação) segundo as 4 fases padrão do xUnit:
      1. Setup - coloca o sistema no estado necessário
      2. Exercise - interage com o objeto sob teste
      3. Verify - checar se o comportamento aconteceu
      4. Teardown - colocar o sistema no estado anterior ao teste
  • Um teste é claro quando é fácil de entender a relação de causa e consequência entre as fases do xUnit.
  • Para avaliar a clareza de um teste basta lê-lo de forma isolada.
  • Ao extrair fragmentos de código exageradamente (aplicar o princípio DRY) dificulta a clareza do teste.
  • Na prática, o uso excessivo de DRY prejudica a clareza do teste.
  • Recomenda-se não aplicar DRY em testes da mesma forma que é aplicado em códigos de produção.
  • Favoreça a clareza do teste sobre DRY.
  • Ao escrever um teste, pense nele como um exemplo de utilização do seu código.
  • Como se tivesse explicando para alguém como utilizar o seu código.
  • Ao pensar dessa maneira, você será forçado a deixar o seu teste claro.
  • Os mocks e stubs são ferramentas clássicas na realização de testes sendo usados quase que diariamente.
  • Porém, muitas pessoas não sabem a diferença entre ambos e/ou não entendem como funcionam.
  • Os mocks não são uma ferramenta somente de teste.
  • O SUT é system under test ou o objeto que está sendo testado.
  • O objeto que está sendo testado possui, normalmente, uma dependência que é passada através do construtor. Essa dependência é chamada de DOC ou depended-on-component ou collaborator.
  • Um test double (um mock ou stub, por exemplo) é quando no seu teste se substitui a dependência real por um objeto simulado (DOC).
  • Os test doubles mais conhecidos são stub, mock, spy, fake e dummy object.
  • O livro xUnit Patterns explica melhor o funcionamento dos test doubles.
  • Por que precisamos de mocks?
  • O conceito de mocks foi introduzido para ajudar no fluxo de desenvolvimento utilizando TDD.
  • O conceito foi introduzido por Steve Freeman através de um paper chamado Endo-Testing: Unit Testing with Mock Objects.
  • Foi descoberto com a técnica de mocks que é possivel fazer software pensando de modo outside-in e ir definindo as APIs internas dos objetos do ponto de vista de quem vai consumi-las.
  • Uma ferramenta para descobrir a API dos colaboradores ou dependências do ponto de vista de quem as consome dentro do processo de desenvolvimento orientado a testes são os mocks.
  • Os mocks surgiram para ajudar a fazer design de modo outside-in.
  • Houveram dificuldades no entendimento do funcionamento de mocks e foi então criado outro paper chamado Mock Roles, not Objects.
  • Recomenda-se a leitura do paper chamado Mock Roles, not Objects.
  • Persistindo as dificuldades, os autores decidiram escreveer um livro, o Growing Object-Oriented Software, Guided by Tests.
  • A interface discovery é o processo de descoberta da API e responsabilidades de novos objetos do seu sistema a partir de quem precisa utilizá-los. Esse é o motivo pelo qual os mocks são criados.
  • Ao invés de verificar a impressão na tela, por exemplo, verifica-se se a comunicação entre os objetos está correta, ou seja, se o método foi chamado.
  • O teste com mocks testa a chamada do método ou envio da mensagem.
  • No teste (1) cria-se o test double, (2) injeta-se o objeto como dependência, (3) cria-se o mock do test double e, por fim, (4) verifica-se se o mock irá receber a mensagem correta.
  • A ordem dos passos do teste muda de (1) setup, (2) exercise e (3) verify para (1) setup, (2) verify e (3) exercise.
  • Pode-se utilizar um spy caso queira-se manter a ordem.
  • Os mocks são utilizados para a fase de verify de um teste e não para a fase de setup como é comumente visto.
  • No teste tradicional verifica-se o estado final do objeto.
  • No teste por comportamento (com mocks) verifica-se a troca de mensagens entre os objetos.
  • A orientação a objetos é menos sobre os objetos e mais sobre a troca de mensagens entre si.
  • Um mock é um teste double utilizado na fase de verify.
  • Mockar um objeto é programá-lo para verificar se ele recebeu as mensagens corretas do SUT. E não programar um objeto para retornar um valor padrão, isso é um stub.
  • O mock foi criado originalmente para ser usado com a técnica de interface discovery.
  • O que é um stub?
  • É um test double utilizado na fase de setup.
  • O conceito de stubar um objeto é programá-lo para retornar um valor padrão.
  • Ao fazer um teste de aceitação que tem como detalhe consumir dados de uma API deve-se stubar uma API e não mockar uma API como todo mundo costuma dizer.
  • A especificação por exemplos é uma técnica ágil para o levantamento de requisitos.
  • Recomenda-se a leitura do livro Specification by Example para o entendimento da técnica.
  • O Cucumber é uma ferramenta de especificação e documentação e não uma ferramenta de testes.
  • As pessoas costumam utilizar o Cucumber para testes de aceitação e testes end-to-end equivocadamente.
  • As ferramentas de specification by example como o Cucumber conforme a metodologia são utilizadas para fazer specs ou documentações executáveis.
  • A ideia é trazer o conceito de documentação tradicional para o mundo ágil.
  • A documentação tradicional (casos de uso e documentos Word) fica desatualizada com o passar do tempo.
  • A documentação executável se mantém atualizada com o passar do tempo.
  • As documentações são importantes e uma forma de mantê-las atualizadas foi juntá-las com os testes automatizados em algo chamado de documentação executável.
  • O processo de especificação por exemplos começa na (1) definição do escopo do software com user stories, (2) especificação e ilustração com exemplos, (3) automatização da especificação e (4) possuir uma documentação viva.
  • A documentação se torna viva.
  • Quando usar Cucumber?
    • Quando o domínio do negócio for complexo
      • o domínio do negócio tem muitos termos que não são de conhecimento público
    • Para algum comportamento do sistema que for muito complexo e houver valor documentá-lo com linguagem natural
      • difícil de entender o propósito do código apenas através da leitura do código
    • Quando houver pessoas que precisam saber o comportamento do sistema mas que não consigam ler o código-fonte
      • suporte, analistas de negócios e outros stakeholders
    • Para documentar um overview do comportamento do sistema
      • exemplo da documentação do RSpec e VCR
  • A fonte autoritativa sobre o comportamento do sistema é o código.
  • Como usar o Cucumber?
    • use a linguagem do domínio do problema, não a de linguagem de interface com usuário
    • escreva a documentação, não apenas automação de testes
    • não precisa usar para todos os testes end-to-end, só para os que envolvem a necessidade de documentação
  • O testing iceberg ou pirâmide caída diz que nem todos os business-readable tests precisam ser end-to-end.
  • Nem todos os testes end-to-end precisam ser legíveis por pessoas de negócio, ou seja, em Cucumber.
  • Conclusão
    • prefira clareza ao invés de DRY nos testes
    • organize sua suíte segundo a pirâmide de testes
    • substitua "testes de aceitação" por testes de view ou testes unitários (a suíte vai ficar mais rápida)
    • testes de aceitação são sobre regras de negócio e não sobre especificação de UI
    • stubs são para a fase de setup e mocks para a fase de verify
    • quando alguém fala mockar provavelmente quer falar stubar
    • os mocks foram criados para fazer outside-in com interface discovery
    • o Cucumber é uma ferramenta de documentação e não de testes (especificação por exemplos)
    • você não precisa usar Cucumber para todos os testes end-to-end da sua aplicação
    • é possível fazer testes business-readable sem ser end-to-end

Outras Referências

Copy link

ghost commented Aug 15, 2018

Muito bom ( :

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment