<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Thalita Marra</title>
    <description>The latest articles on Forem by Thalita Marra (@thalimarra).</description>
    <link>https://forem.com/thalimarra</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F419913%2F6cfaf0ea-27cd-4b5c-8bae-122ef4568a7a.png</url>
      <title>Forem: Thalita Marra</title>
      <link>https://forem.com/thalimarra</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/thalimarra"/>
    <language>en</language>
    <item>
      <title>Testes de Contrato</title>
      <dc:creator>Thalita Marra</dc:creator>
      <pubDate>Fri, 29 Sep 2023 18:46:43 +0000</pubDate>
      <link>https://forem.com/thalimarra/testes-de-contrato-47kl</link>
      <guid>https://forem.com/thalimarra/testes-de-contrato-47kl</guid>
      <description>&lt;p&gt;Tive a fantástica oportunidade de poder compartilhar um pouco dos meus problemas e estudos atuais na forma de uma palestra no PHP Community Summit 23 (galera do PHPSP, vcs arrasam!) e fiquei devendo compartilhar a apresentação com a comunidade, então aqui está:&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
      &lt;div class="c-embed__cover"&gt;
        &lt;a href="https://docs.google.com/presentation/d/e/2PACX-1vT0_dWs_rpNJYzru0rrhVQTAmpt-PitfjBQeojCE0NG5bRDdfh1BYDxi9RXEnv51GHmPrSSQqKM1qGF/pub?start=false&amp;amp;amp%3Bloop=false&amp;amp;amp%3Bdelayms=3000" class="c-link s:max-w-50 align-middle" rel="noopener noreferrer"&gt;
          &lt;img alt="" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flh7-us.googleusercontent.com%2Fdocs%2FAHkbwyInOp7v4soRj_bgGT3vCs_clf_uUOjl-kREgKqN-_2HdbKVG2b-jzyCkUZjS1wFhYBFPlx3upY1oDEeqEAsqjzvv0LVMIjOhXOvXHvOWScP1r0Pc9fK%3Dw1200-h630-p" height="auto" class="m-0"&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;div class="c-embed__body"&gt;
      &lt;h2 class="fs-xl lh-tight"&gt;
        &lt;a href="https://docs.google.com/presentation/d/e/2PACX-1vT0_dWs_rpNJYzru0rrhVQTAmpt-PitfjBQeojCE0NG5bRDdfh1BYDxi9RXEnv51GHmPrSSQqKM1qGF/pub?start=false&amp;amp;amp%3Bloop=false&amp;amp;amp%3Bdelayms=3000" rel="noopener noreferrer" class="c-link"&gt;
          Testes de Contrato - PHP Summit - Google Slides
        &lt;/a&gt;
      &lt;/h2&gt;
      &lt;div class="color-secondary fs-s flex items-center"&gt;
          &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fssl.gstatic.com%2Fdocs%2Fpresentations%2Fimages%2Ffavicon-2023q4.ico"&gt;
        docs.google.com
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// TODO voltar e colocar o video do YouTube 😅&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois de sei lá quanto tempo estar de volta à comunidade que me acolheu alguns anos atrás foi super gratificante e inspirador 💙&lt;/p&gt;

&lt;p&gt;Espero que o conteúdo também seja relevante pra vocês e fico à disposição :) &lt;/p&gt;

</description>
      <category>testing</category>
      <category>braziliandevs</category>
      <category>pact</category>
      <category>postman</category>
    </item>
    <item>
      <title>Git e GitHub</title>
      <dc:creator>Thalita Marra</dc:creator>
      <pubDate>Fri, 24 Feb 2023 23:03:15 +0000</pubDate>
      <link>https://forem.com/thalimarra/git-e-github-53h3</link>
      <guid>https://forem.com/thalimarra/git-e-github-53h3</guid>
      <description>&lt;ul&gt;
&lt;li&gt;O que é Git&lt;/li&gt;
&lt;li&gt;Onde o GitHub entra nessa história&lt;/li&gt;
&lt;li&gt;
Como isso se encaixa no dia a dia de uma pessoa desenvolvedora

&lt;ul&gt;
&lt;li&gt;Concluir as configurações necessárias&lt;/li&gt;
&lt;li&gt;Iniciar o projeto com o Git&lt;/li&gt;
&lt;li&gt;Atuar no projeto&lt;/li&gt;
&lt;li&gt;Salvar minhas alterações&lt;/li&gt;
&lt;li&gt;Juntar o código novo com o código principal&lt;/li&gt;
&lt;li&gt;Atualizar o projeto local&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Resumindo&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  O que é Git
&lt;/h2&gt;

&lt;p&gt;Segundo nossa querida &lt;a href="https://pt.wikipedia.org/wiki/Git"&gt;Wikipedia&lt;/a&gt;, o Git é um sistema de controle de versões distribuído. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;E o que isso significa?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Deixa eu tentar explicar com um exemplo:&lt;/p&gt;

&lt;p&gt;Suponha que estamos trabalhando em uma plataforma muito grande, onde funcionalidades são atualizadas e criadas constantemente. Em determinado momento alguém fala para apagarmos uma funcionalidade que era difícil de manter e não estava sendo usada. Fazemos isso, simplificamos bastante coisa no nosso código e seguimos criando e atualizando outras coisas. Meses se passam e um belo dia alguém fala que vai precisar daquela funcionalidade que apagamos. E agora?&lt;/p&gt;

&lt;p&gt;Se nosso projeto estiver usando o Git, podemos voltar na &lt;em&gt;ramificação&lt;/em&gt; que tinha aquela funcionalidade (aquele “controle de versão” da definição da Wikipedia) e pensar em estratégias para integrar esse código apagado novamente. Não seria necessário criar tudo do zero.&lt;/p&gt;

&lt;p&gt;Com o Git, cada pessoa que tiver &lt;em&gt;clonado&lt;/em&gt; o repositório terá uma cópia local do histórico completo da versão do projeto. Alterações podem ser feitas na sua máquina e enviadas para o repositório principal depois, assim várias pessoas podem atuar no projeto ao mesmo tempo (inclusive no mesmo arquivo) sem que uma alteração afete os outros.&lt;/p&gt;

&lt;h2&gt;
  
  
  Onde o GitHub entra nessa história
&lt;/h2&gt;

&lt;p&gt;O GitHub é uma &lt;strong&gt;plataforma&lt;/strong&gt; que usa Git. É como se alguém tivesse baixado o Git em um servidor, feito uma tela maneira, colocado algumas funcionalidades a mais e disponibilizado em nuvem pra gente usar. Assim como o GitHub, existem várias outras plataformas que usam o Git por trás dos panos, como o &lt;a href="https://about.gitlab.com/"&gt;GitLab&lt;/a&gt; e &lt;a href="https://bitbucket.org/"&gt;Bitbucket&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Como isso se encaixa no dia a dia de uma pessoa desenvolvedora
&lt;/h2&gt;

&lt;p&gt;Falando sobre o &lt;em&gt;meu&lt;/em&gt; dia a dia enquanto desenvolvedora, muita coisa gira ao redor do Git / GitHub.&lt;/p&gt;

&lt;h3&gt;
  
  
  Concluir as configurações necessárias
&lt;/h3&gt;

&lt;p&gt;Após instalado, precisamos configurar o Git. Sua configuração inicial precisa incluir o nome e email da autoria de mudanças enviadas por determinada máquina.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;git config&lt;/code&gt; - as configurações do Git precisam ser feitas apenas uma vez se usarmos a opção &lt;code&gt;--global&lt;/code&gt; ou por diretório se usarmos a opção &lt;code&gt;--local&lt;/code&gt;. &lt;a href="https://git-scm.com/docs/git-config/pt_BR"&gt;Existe uma lista enorme de coisas que podemos configurar&lt;/a&gt;, mas as principais são o nome (&lt;code&gt;git config --global user.name "Seu Nome"&lt;/code&gt;) e email (&lt;code&gt;git config --global user.email "seu@email.com"&lt;/code&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Iniciar o projeto com o Git
&lt;/h3&gt;

&lt;p&gt;Logo que começo a atuar em um projeto, uma das primeiras coisas a fazer é clonar o repositório e ler as instruções (normalmente encontradas no arquivo &lt;code&gt;README.md&lt;/code&gt; na raiz do projeto).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;git clone url_do_projeto&lt;/code&gt; - clonar um projeto significa fazer uma cópia do repositório na minha máquina, para que eu possa acessá-lo e atuar nele localmente. Normalmente é uma ação feita apenas uma vez por projeto.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://docs.github.com/pt/repositories/creating-and-managing-repositories/cloning-a-repository"&gt;O GitHub tem uma documentação boa sobre como clonar projetos&lt;/a&gt;. A minha opção preferida é clonar via SSH já que não preciso ficar validando minha identidade repetidamente. &lt;a href="https://docs.github.com/pt/authentication/connecting-to-github-with-ssh/about-ssh"&gt;O GitHub também tem uma documentação detalhando como isso funciona.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Caso seja um projeto 100% novo, posso criar a base dele na minha máquina para então iniciar o Git localmente e enviar para o repositório no GitHub.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;git init&lt;/code&gt; - iniciar um repositório também costuma ser uma ação feita apenas uma vez. Esse comando vai criar uma pasta chamada &lt;code&gt;.git&lt;/code&gt; na raiz do projeto contendo todos os metadados do repositório e habilitar o uso dos demais comandos do git para aquele projeto.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Para criar o repositório no GitHub, basta seguir &lt;a href="https://docs.github.com/pt/repositories/creating-and-managing-repositories/creating-a-new-repository"&gt;a documentação deles&lt;/a&gt; que não tem muita surpresa.&lt;/p&gt;

&lt;h3&gt;
  
  
  Atuar no projeto
&lt;/h3&gt;

&lt;p&gt;Uma vez que tenho o código disponível na minha máquina, posso começar a atuar em alterações. Para isso crio uma nova ramificação (ou &lt;em&gt;branch&lt;/em&gt;) a partir da ramificação principal, normalmente chamada de &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Um &lt;strong&gt;branch&lt;/strong&gt; é um &lt;strong&gt;snapshot&lt;/strong&gt; do código em determinado momento, uma "cópia" isolada do código tal qual está. Dessa forma podemos testar coisas, mudar comportamentos, etc, sem que nossas ações afetem as demais versões do projeto.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;git checkout -b minha-tarefa&lt;/code&gt; - o comando &lt;code&gt;git checkout&lt;/code&gt;, quando usado dessa forma, é responsável por mudar de branch; a opção &lt;code&gt;-b&lt;/code&gt; criará um novo branch com o nome informado a seguir (nesse exemplo, &lt;code&gt;minha-tarefa&lt;/code&gt;).&lt;br&gt;
Vale comentar aqui que o &lt;code&gt;-b&lt;/code&gt; veio como uma forma de chamar o comando &lt;code&gt;git branch&lt;/code&gt; (que lista, cria, renomeia e exclui branches) junto ao &lt;code&gt;git checkout&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Salvar minhas alterações
&lt;/h3&gt;

&lt;p&gt;Gosto de separar meu desenvolvimento em fases. Então assim que termino partes do que estou fazendo posso "nomear" aquele pacote de alterações e criar um histórico de coisas que executei.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;git add [nome dos arquivos]&lt;/code&gt; - primeiro é necessário falar quais arquivos vou incluir em determinado "pacote" de alteração, seja colocando o nome dos mesmos separados por espaço (ex.: &lt;code&gt;hello.html hello.css&lt;/code&gt;), seja usando um &lt;code&gt;.&lt;/code&gt; para incluir tudo de determinado diretório, ou &lt;code&gt;--all&lt;/code&gt; para adicionar todos os arquivos alterados em todos os diretórios.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git commit -m "uma mensagem"&lt;/code&gt; - depois de ter todos os arquivos selecionados, preciso adicionar uma mensagem que explica a alteração que foi feita.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Usando esses comandos, se alguma alteração que fiz der errado, posso consultar o histórico do meu branch e voltar para determinado ponto do desenvolvimento, se necessário for.&lt;/p&gt;

&lt;p&gt;Bem, até então tudo o que foi desenvolvido está apenas na minha máquina e preciso enviar isso para o GitHub (ou qualquer outra plataforma que estiver usando). Normalmente costumo enviar as alterações que fiz ao final do dia (vai que minha máquina pega fogo, nunca se sabe...) ou quando o desenvolvimento está concluído.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;git push origin minha-tarefa&lt;/code&gt; - aqueles commits que fiz anteriormente serão "empurrados" do branch &lt;code&gt;minha-tarefa&lt;/code&gt; da máquina local para o ambiente remoto (o repositório "origem" no GitHub), em um branch que também será chamado de &lt;code&gt;minha-tarefa&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Dá pra usar o comando &lt;code&gt;git push&lt;/code&gt; de algumas formas diferentes. Achei um &lt;a href="https://blog.betrybe.com/git/git-push/"&gt;artigo da Trybe&lt;/a&gt; muito maneiro que entra em mais detalhes, caso queira.&lt;/p&gt;

&lt;h3&gt;
  
  
  Juntar o código novo com o código principal
&lt;/h3&gt;

&lt;p&gt;Uma vez que terminei tudo o que tinha para fazer naquela tarefa posso abrir um Pull Request (ou PR). Em resumo, o PR vai disponibilizar o código que eu criei para ser revisado por outras pessoas que trabalham comigo (e por mim mesma também) e, caso esteja tudo certo, juntá-lo ao código principal (ação chamada &lt;em&gt;merge&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_DQCt3NK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v6232hn3838l4i9m9l2y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_DQCt3NK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v6232hn3838l4i9m9l2y.png" alt="Print da tela do GitHub no processo de abertura de Pull Request" width="880" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Na imagem estamos abrindo um Pull Request no GitHub. Queremos juntar nosso código no código principal, então configuramos a base como &lt;code&gt;main&lt;/code&gt; (o branch principal) e comparamos com o branch que atuamos, &lt;code&gt;minha-tarefa&lt;/code&gt;. Para que as outras pessoas saibam o que aquele PR trata, colocamos um título resumindo a tarefa que estamos entregando e uma descrição explicando o objetivo daquele código, dando exemplos de como testar, adicionando detalhes importantes sobre as regras que aquele código deve seguir, etc.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://docs.github.com/pt/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests"&gt;O GitHub tem uma documentação bem detalhada sobre como funciona esse processo&lt;/a&gt;. Existem várias customizações que podem ser feitas, é bem legal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Atualizar o projeto local
&lt;/h3&gt;

&lt;p&gt;Uma vez que terminei minhas alterações, preciso voltar para o branch principal e buscar a versão mais atual dele, para, só então, começar a trabalhar em uma nova tarefa.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;git checkout main&lt;/code&gt; - usado para voltar ao branch principal. Aqui não é necessário usar a opção &lt;code&gt;-b&lt;/code&gt; pois a ramificação &lt;code&gt;main&lt;/code&gt; já existe.&lt;br&gt;
&lt;code&gt;git pull origin main&lt;/code&gt; - "puxa" para a máquina local todas as alterações que estiverem no branch &lt;code&gt;main&lt;/code&gt; da origem, o repositório no GitHub.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Resumindo
&lt;/h2&gt;

&lt;p&gt;É difícil colocar todos os comandos do Git em um único post, mas esses são os principais do meu dia a dia. Vou deixar um resumo para download pra facilitar o acesso:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://drive.google.com/file/d/1_e2prG6ZG0k7e8rkGNfmbApnV8AmEvRc/view"&gt;Baixar como PDF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://drive.google.com/file/d/1893Dw_ohUJMfc4dA7ncSjY1RakV-4CDU/view"&gt;Baixar como imagem&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Se aparecer qualquer dúvida pode colocar aqui nos comentários que tento responder assim que possível.&lt;/p&gt;

&lt;p&gt;Até a próxima!&lt;/p&gt;

</description>
      <category>git</category>
      <category>github</category>
      <category>beginners</category>
    </item>
    <item>
      <title>5 dicas de como escrever um bom desafio técnico</title>
      <dc:creator>Thalita Marra</dc:creator>
      <pubDate>Mon, 28 Jun 2021 18:49:49 +0000</pubDate>
      <link>https://forem.com/thalimarra/5-dicas-de-como-escrever-um-bom-desafio-tecnico-kj0</link>
      <guid>https://forem.com/thalimarra/5-dicas-de-como-escrever-um-bom-desafio-tecnico-kj0</guid>
      <description>&lt;p&gt;Olá olá!&lt;/p&gt;

&lt;p&gt;Esses dias estava passeando pelos meus repositórios do GitHub e vi um dos últimos desafios técnicos que fiz por lá. Refletindo um pouco sobre ele e sobre tudo o que eu aprendi enquanto entrevistadora técnica na minha empresa atual decidi fazer um compilado de dicas que eu daria pra mim mesma naquela época.&lt;br&gt;
Bem, lhes apresento a minha lista de 5 dicas de como escrever um bom desafio técnico:&lt;/p&gt;

&lt;h2&gt;
  
  
  Entenda o problema
&lt;/h2&gt;

&lt;p&gt;Durante o desafio técnico (seja escrevendo código ou whiteboard), a primeira coisa que precisa ficar clara é &lt;strong&gt;qual o problema que você vai ter que resolver&lt;/strong&gt;. Quanto menor for o seu nível de dúvidas, maior é a possibilidade de entregar uma solução assertiva e, ouso dizer, gerando uma entrega com mais confiança até.&lt;/p&gt;

&lt;p&gt;Os envolvidos na entrevista técnica estão preparado para tirar suas dúvidas e (pelo menos nas entrevistas que já participei) isso não afeta em nada o resultado daquela etapa. Pode perguntar sem medo!&lt;/p&gt;

&lt;p&gt;Aqui também vale destacar a importância de confirmar se todos os contratos estão sendo cumpridos uma vez que a solução estiver pronta. &lt;/p&gt;

&lt;p&gt;Se o desafio for escrever uma API por exemplo, confirme se os retornos, rotas e validações estão de acordo com o descrito no problema, veja se os pré-requisitos funcionais e não funcionais do código foram atendidos. &lt;/p&gt;

&lt;p&gt;Um detalhe importante é que não é incomum seu projeto ser testado de forma automática. Então se no desafio você precisa criar uma rota para a url &lt;code&gt;/create-user&lt;/code&gt; e você escreve &lt;code&gt;/createUser&lt;/code&gt;, pode ser que o teste não passe e isso acabe te atrapalhando. Novamente, confirme se os requisitos foram atendidos.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Não deixe de entregar seu desafio porque não conseguir completá-lo. O ideal é entregar tudo de acordo com o que foi pedido, mas não é impossível passar em uma vaga sem ter concluído 100% do desafio.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Explique seu repositório
&lt;/h2&gt;

&lt;p&gt;Nada me deixa mais triste com um repositório do que a falta de documentação. O que eu preciso instalar pra fazer o projeto rodar? Quais comandos eu preciso chamar para conseguir fazer o que precisa? Existe Docker? Tem alguma coisa de fora da linguagem que eu preciso? Alguma configuração?&lt;/p&gt;

&lt;p&gt;É extremamente importante que a pessoa que vai avaliar sua solução consiga saber facilmente como ela funciona. Inclusive pessoas de outros lugares. Seu GitHub, GitLab, Bitbucket, etc, é um portfólio e pode ser seu grande aliado.&lt;/p&gt;

&lt;p&gt;Tire um tempo para atualizar o README e, pelo menos, explicar a ideia geral do projeto, como instalar e como utilizar. E &lt;strong&gt;confirme&lt;/strong&gt; se tudo funciona conforme o descrito.&lt;/p&gt;

&lt;h2&gt;
  
  
  Destaque para a lógica
&lt;/h2&gt;

&lt;p&gt;Muitas vezes vemos nas vagas alguma menção à framework. Então assumimos que para escrever uma boa solução precisaremos usar aquele framework e demonstrar nosso conhecimento sobre ele. Só que nem sempre é assim.&lt;/p&gt;

&lt;p&gt;Quem vai avaliar precisa entender como é seu processo criativo, o que você pensou até chegar em uma solução e como você trabalha.&lt;/p&gt;

&lt;p&gt;O uso de um framework me faz lembrar de dois possíveis problemas logo de cara:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Às vezes a solução enviada está tão acoplada com as funcionalidades existentes no framework que é impossível avaliar como é o código de quem entregou. Código gerado pelo framework é bem diferente do código que nós escrevemos no dia a dia.&lt;/li&gt;
&lt;li&gt;Quando uma solução depende demais das features disponíveis no framework pode ser que a solução enviada seja muito mais complexa do que o necessário.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Não é ruim usar frameworks ou bibliotecas, mas crie algo que demonstre sua linha de raciocínio, algo que você entenda porque funciona, como funciona, que você acredita que seja a forma mais otimizada de resolver algo e que vai saber explicar posteriormente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demonstre conhecer a tecnologia utilizada
&lt;/h2&gt;

&lt;p&gt;Aqui é meio que uma extensão da dica anterior. Demonstrar que você conhece funcionalidades da linguagem escolhida que não estão no framework vai te ajudar, conseguir explicar porque usou determinado banco ou determinada biblioteca também vai te ajudar. &lt;/p&gt;

&lt;p&gt;Saiba os motivos pelos quais está usando a tecnologia que você escolheu. Pode ser que você esteja aplicando para uma vaga de níveis iniciais e só usou o MySQL porque está acostumado com isso, então esse é seu motivo e tudo bem. Mas a medida que o nível das vagas vai aumentando, essa exigência também vai aumentando, então questione as decisões que você toma automaticamente e veja se fazem sentido para o contexto do desafio proposto.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lembre-se das melhores práticas
&lt;/h2&gt;

&lt;p&gt;Um código bom é um código que funciona e que também é legível. Não existe essa de que só funcionar está bom, ainda mais em um momento onde seu código é avaliado.&lt;/p&gt;

&lt;p&gt;Algumas vagas, pelo menos na minha bolha de PHP, fazem menção a algo chamado PSR (&lt;em&gt;PHP Standard Recommendation&lt;/em&gt;) que nada mais é do que uma lista de boas práticas para escrita de código. Fala sobre formatação, nomenclaturas, estilo de código, etc. Esse é um detalhe que costuma ser visto com bastante carinho, não necessariamente uma exigência, mas algo que vai te ajudar.&lt;/p&gt;

&lt;p&gt;Veja se a linguagem que está usando também possui um guia de melhores práticas e se atenha a elas. Deixe seu código legível, use terminologias com consistência, escolha bons nomes para classes, funções e variáveis e não escreva comentários sem necessidade.&lt;/p&gt;




&lt;p&gt;Bom, é isso. Espero que seja de alguma ajuda. Se quiserem deixar mais dicas aqui nos comentários ou tirar alguma dúvida, o espaço é nosso!&lt;/p&gt;

&lt;p&gt;Até a próxima!&lt;/p&gt;

</description>
      <category>womenintech</category>
      <category>braziliandevs</category>
      <category>career</category>
      <category>devjournal</category>
    </item>
    <item>
      <title>Introdução ao desenvolvimento guiado por testes (TDD)</title>
      <dc:creator>Thalita Marra</dc:creator>
      <pubDate>Mon, 14 Jun 2021 18:33:11 +0000</pubDate>
      <link>https://forem.com/thalimarra/introducao-ao-desenvolvimento-guiado-por-testes-tdd-42ed</link>
      <guid>https://forem.com/thalimarra/introducao-ao-desenvolvimento-guiado-por-testes-tdd-42ed</guid>
      <description>&lt;p&gt;Olá olá!&lt;/p&gt;

&lt;p&gt;Essa é a última postagem da série de Introdução a Testes de Software e quero terminar plantando a sementinha do TDD no arsenal de vocês 🌱&lt;/p&gt;

&lt;h2&gt;
  
  
  O que é TDD?
&lt;/h2&gt;

&lt;p&gt;TDD é uma sigla para &lt;em&gt;Test Driven Development&lt;/em&gt; (ou Desenvolvimento Guiado por Testes) que na prática significa exatamente o que o nome diz: primeiro escrevemos os testes, depois o código de produção.&lt;/p&gt;

&lt;p&gt;Colocar o TDD em prática significa trabalhar de forma cíclica: primeiro criamos os testes necessários, que irão falhar; depois vamos escrever o mínimo possível de código para os testes passarem; por fim, se necessário, refatoramos o que foi feito. Bem simples!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fri6ms1o7n2aecgfmbume.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fri6ms1o7n2aecgfmbume.png" alt="Ciclo do TDD - novo teste com erro (vermelho), o mínimo de código para passar o teste (verde), refatorar (azul)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A princípio pode parecer meio complexo, mas vamos ver um exemplo prático e vai ficar mais claro uma vez que chegarmos lá.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modelo F.I.R.S.T.
&lt;/h2&gt;

&lt;p&gt;Quando seguimos o ciclo do TDD é normal ter uma quantidade considerável de testes cobrindo praticamente todo o nosso código de produção. &lt;/p&gt;

&lt;p&gt;Chega um momento em que o tamanho dos testes acompanha o tamanho do código de produção, e isso pode se tornar um problema de gerenciamento assustador. Sendo assim, é necessário tratar os testes com o mesmo cuidado que o código de produção.&lt;/p&gt;

&lt;p&gt;O modelo F.I.R.S.T. existe para ajudar nesse processo e cada letra do acrônimo representa um princípio a ser seguido:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fast&lt;/strong&gt; (rapidez): os testes devem ser rápidos. Quando eles são lentos se torna tentador não executá-los com frequência, trazendo problemas como encontrar um bug tardiamente, quando for mais difícil de concertá-lo ou quando ele já afetar outras áreas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolates&lt;/strong&gt; (isolamento): um teste não deve depender de outro, eles precisam ser executados de forma independente e em qualquer ordem. Dessa forma fica fácil de encontrar onde e porque alguma falha acontece.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repeateble&lt;/strong&gt; (repetitividade): devemos ser capaz de executar os testes unitários em qualquer ambiente, com resultados e comportamentos constantes. Eles não devem depender de algum estado prévio (de um banco de dados já preenchido, por exemplo) e devem deixar o ambiente tal qual estava antes de serem iniciados. Devem rodar com ou sem internet, no seu ambiente local ou no ambiente de produção. Se um teste não roda fora de um ambiente específico, eles não vão te ajudar em todas as situações que poderiam.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-validating&lt;/strong&gt; (autovalidação): os testes devem resultar em sucesso ou erro, eles não podem depender de alguém validando seu resultado manualmente. Um resultado de erro ou sucesso não deve ser subjetivo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timely&lt;/strong&gt; (pontualidade): os testes precisam ser escritos no momento certo. No TDD é importante que o teste seja feito antes do desenvolvimento do código de produção. Deixar o teste para depois pode fazer com que eles sejam ignorados ou que não cubram quantos casos poderiam se o fluxo correto fosse seguido.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Exemplo prático
&lt;/h2&gt;

&lt;p&gt;Precisamos desenvolver um sistema de biblioteca e vamos começar pelo cadastro dos livros. Os requisitos são:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;01:&lt;/strong&gt; A biblioteca deve possuir livros&lt;br&gt;
&lt;strong&gt;02:&lt;/strong&gt; Deve ser possível navegar por todos os livros disponíveis na biblioteca&lt;/p&gt;

&lt;p&gt;Então seguindo o ciclo do TDD, começamos escrevendo um teste de falha:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;01.01. Criar um teste que falhe (vermelho)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Vamos começar a descrever nossa regra de negócio através do teste:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testBibliotecaPossuiLivros&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$book&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Aqueles olhos verdes'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Pedro Bandeira'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$library&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Library&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$library&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;nextBook&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="nv"&gt;$library&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$book&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$book&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$library&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;nextBook&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$library&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quando o PHPUnit executar nosso teste iremos receber um erro:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PHPUnit 9.5.5 by Sebastian Bergmann and contributors.

E                                                                   1 / 1 (100%)

Time: 00:00.064, Memory: 4.00 MB

There was 1 error:

1) Tests\BooksTest::testBibliotecaPossuiLivros
Error: Class "Tests\Book" not found

/app/tests/BooksTest.php:13

ERRORS!
Tests: 1, Assertions: 0, Errors: 1.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como a única coisa que fizemos até então foi criar o teste, precisamos criar as classes e métodos necessários para fazer o teste passar.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;01.02. Fazer os testes passarem (verde)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Começamos criando a classe &lt;code&gt;Book&lt;/code&gt; e como a única coisa que precisamos nesse momento é a classe com o construtor, então ficou algo bem genérico:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Book&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$author&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$author&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$author&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Já a classe &lt;code&gt;Library&lt;/code&gt; precisa do método &lt;code&gt;count()&lt;/code&gt; para passar no &lt;code&gt;assertCount&lt;/code&gt;. Vamos implementar a interface nativa do PHP &lt;code&gt;Countable&lt;/code&gt; para resolver essa etapa. Também precisamos do método &lt;code&gt;add()&lt;/code&gt; para salvar o livro na biblioteca e do método &lt;code&gt;nextBook()&lt;/code&gt; para iterar sobre os livros disponíveis.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Library&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;\Countable&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$books&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Book&lt;/span&gt; &lt;span class="nv"&gt;$book&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$book&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;nextBook&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;?Book&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Da forma que a classe &lt;code&gt;Library&lt;/code&gt; foi criada, o método &lt;code&gt;nextBook&lt;/code&gt; retorna apenas o primeiro livro existente na biblioteca, quando houver. Não precisamos nos preocupar com isso agora porque não temos nenhum teste validando o processo de iteração nos livros, precisamos apenas que os testes passem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PHPUnit 9.5.5 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 00:00.068, Memory: 4.00 MB

OK (1 test, 3 assertions)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;01.03. Refatorar o código escrito (azul)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Agora sim fazemos melhorias naquele código que escrevemos anteriormente. Como ainda é o começo do nosso sistema e não tem muita coisa para mexer, talvez nem fosse preciso refatorar nada, mas vamos colocar um operador ternário no método &lt;code&gt;nextBook&lt;/code&gt; para diminuir um pouco o código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;nextBook&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;?Book&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E rodamos o teste novamente para ter certeza de que nada quebrou:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PHPUnit 9.5.5 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 00:00.067, Memory: 4.00 MB

OK (1 test, 3 assertions)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora precisamos fazer com que a segunda parte dos nossos requisitos seja atendida: o método &lt;code&gt;nextBook&lt;/code&gt; deve navegar por todos os livros disponíveis na biblioteca.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;02.01. Criar um teste que falhe (vermelho)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Vamos criar um roteiro de como o sistema deveria funcionar, criando os livros, adicionando eles à biblioteca e passando por todos os ítens disponíveis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testNavegarPorTodosOsLivros&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$book1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'O Mundo de Sofia'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Jostein Gaarder'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$book2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'O Silmarillion'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'J. R. R. Tolkien'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$library&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Library&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nv"&gt;$library&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$book1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$library&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$book2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$book1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$library&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;nextBook&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$book2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$library&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;nextBook&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ao executar esse teste no PHPUnit vemos que ele irá falhar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PHPUnit 9.5.5 by Sebastian Bergmann and contributors.

F                                                                   1 / 1 (100%)

Time: 00:00.087, Memory: 4.00 MB

There was 1 failure:

1) Tests\BooksTest::testNavegarPorTodosOsLivros
Failed asserting that two objects are equal.
--- Expected
+++ Actual
@@ @@
 App\Book Object (
-    'name' =&amp;gt; 'O Silmarillion'
-    'author' =&amp;gt; 'J. R. R. Tolkien'
+    'name' =&amp;gt; 'O Mundo de Sofia'
+    'author' =&amp;gt; 'Jostein Gaarder'
 )

/app/tests/BooksTest.php:35

FAILURES!
Tests: 1, Assertions: 2, Failures: 1.
ERROR: 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aqui o PHPUnit falou que fez duas afirmações e apenas uma delas falhou (&lt;code&gt;Assertions: 2, Failures: 1&lt;/code&gt;). Isso foi porque o primeiro item sempre está retornando, então pesquisar apenas pelo primeiro item iria funcionar. O problema está quando vamos pesquisar a partir do segundo item.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;02.02. Fazer os testes passarem (verde)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Vamos mexer na classe &lt;code&gt;Library&lt;/code&gt; para que o método &lt;code&gt;nextBook&lt;/code&gt; passe por todos os livros disponíveis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Library&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;\Countable&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$books&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$nextBookIdx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Book&lt;/span&gt; &lt;span class="nv"&gt;$book&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$book&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;nextBook&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;?Book&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;nextBookIdx&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$book&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;nextBookIdx&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;nextBookIdx&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$book&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adicionamos à classe uma variável chamada &lt;code&gt;$nextBookIdx&lt;/code&gt; que represente qual o índice do próximo livro a ser retornado e usamos essa variável na função &lt;code&gt;nextBook()&lt;/code&gt;, retornando o livro correspondente caso ele exista.&lt;/p&gt;

&lt;p&gt;Ao chamar o PHPUnit vemos que tanto o novo teste quanto o anterior estão passando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PHPUnit 9.5.5 by Sebastian Bergmann and contributors.

..                                                                  2 / 2 (100%)

Time: 00:00.068, Memory: 4.00 MB

OK (2 tests, 5 assertions)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;02.03. Refatorar o código escrito (azul)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Como a variável &lt;code&gt;$nextBookIdx&lt;/code&gt; só é usada dentro do &lt;code&gt;nextBook()&lt;/code&gt; e &lt;code&gt;$books&lt;/code&gt; é um array, podemos usar as funções nativas do PHP &lt;code&gt;current()&lt;/code&gt; e &lt;code&gt;next()&lt;/code&gt; para resolver a navegação, removendo a necessidade da variável &lt;code&gt;$nextBookIdx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Library&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;\Countable&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$books&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Book&lt;/span&gt; &lt;span class="nv"&gt;$book&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$book&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;nextBook&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;?Book&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$book&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;current&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$book&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;books&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$book&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para quem ainda não está familiarizado com essas funções do PHP, a documentação explica muito bem o que elas fazem, mas de forma geral o que acontece é o seguinte:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cada array possui um ponteiro interno para seu elemento atual, que é inicializado para o primeiro elemento inserido no array. O método &lt;code&gt;current()&lt;/code&gt; retorna o elemento atual ou &lt;code&gt;false&lt;/code&gt; caso não exista nada para retornar.&lt;/li&gt;
&lt;li&gt;A função &lt;code&gt;next()&lt;/code&gt; avança o ponteiro, retornando &lt;code&gt;false&lt;/code&gt; caso não exista um próximo item.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Confirmamos que os testes permanecem sem erros:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PHPUnit 9.5.5 by Sebastian Bergmann and contributors.

..                                                                  2 / 2 (100%)

Time: 00:00.066, Memory: 4.00 MB

OK (2 tests, 5 assertions)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se fosse preciso adicionar novas funcionalidades ao sistema continuaríamos nesse mesmo fluxo: criar um teste de falha → escrever o mínimo de código para fazer teste passar → melhorar o código. Não tem muito segredo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Por que usar?
&lt;/h2&gt;

&lt;p&gt;Todo esse processo pode parecer tedioso mas essa prática nos traz muitos benefícios durante o desenvolvimento e manutenção do sistema. Para finalizar queria deixar aqui os benefícios que percebi enquanto usava o TDD:&lt;/p&gt;

&lt;h3&gt;
  
  
  Qualidade de código
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;"Se algo não é possível ser testado, então foi desenvolvido de forma ruim."&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;— Código Limpo, cap. 09&lt;/p&gt;

&lt;p&gt;Se nós criamos um código com muito acoplamento ou de alta complexidade não vamos querer testá-lo porque vai dar muito trabalho ou vai ser totalmente inviável. Começar escrevendo o teste e apenas o mínimo de código necessário nos força a pensar em como fazer as coisas de maneira mais simples e desacoplada possível.&lt;/p&gt;

&lt;h3&gt;
  
  
  Entendimento sobre o problema
&lt;/h3&gt;

&lt;p&gt;Para escrever um teste nós precisamos entender bem o problema que estamos resolvendo e qual resultado queremos chegar. Descrever a ideia através do teste é como criar um roteiro dizendo como a aplicação precisa funcionar. Dessa forma não criamos coisas nem de mais e nem de menos, já criamos um código voltado para a solução esperada.&lt;/p&gt;

&lt;h3&gt;
  
  
  Segurança e produtividade
&lt;/h3&gt;

&lt;p&gt;Quando a gente altera um código existe a chance dessa alteração causar algum tipo de imprevisto. Quando temos uma aplicação com alta cobertura de testes automatizados essa chance é menor. E se não precisamos nos preocupar tanto em quebrar alguma coisa ou em fazer testes manuais, sentimos mais segurança naquilo que estamos fazendo e ganhamos tempo para outras atividades. &lt;/p&gt;

&lt;p&gt;Existe também o benefício de quando uma pessoa nova entra no time ou quando voltamos a mexer em um código que não vemos há semanas, os testes vão lembrar de todas as excessões que podem acontecer, todas as situações que precisam funcionar de certa maneira. Todos os contratos de como a aplicação deve funcionar estão assegurados.&lt;/p&gt;

&lt;h3&gt;
  
  
  Documentação
&lt;/h3&gt;

&lt;p&gt;Os testes do seu código podem ser a melhor documentação que você vai ter. Eles te dizem o que funciona, como funciona, quais dependências estão envolvidas, quais os possíveis fluxos de erros, etc. E através do TDD, seus testes sempre estarão tão ou mais atualizados quanto o desenvolvimento, não haverá nenhum atraso.&lt;/p&gt;




&lt;p&gt;Bom, é isso. Como sempre, se ficou alguma dúvida pode deixar aqui nos comentários que eu respondo assim que possível!&lt;/p&gt;

&lt;p&gt;Se quiserem baixar o código é só acessar o &lt;a href="https://github.com/thmarra/intro-tdd" rel="noopener noreferrer"&gt;repositório no GitHub&lt;/a&gt;. Cada etapa do ciclo que fizemos aqui pode ser encontrada lá na lista de branches ou de commits.&lt;/p&gt;

&lt;p&gt;Fico por aqui e até a próxima!&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Fonte:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.php.net" rel="noopener noreferrer"&gt;Documentação do PHP&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://laracasts.com/series/php-testing-jargon" rel="noopener noreferrer"&gt;PHP Testing Jargon&lt;/a&gt;, Laracasts.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://agileinaflash.blogspot.com/2009/02/first.html" rel="noopener noreferrer"&gt;F.I.R.S.T&lt;/a&gt;, Tim Ottinger &amp;amp; Jeff Langr&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/@pablodarde/testes-unit%C3%A1rios-com-tdd-test-driven-development-657f3dadad06" rel="noopener noreferrer"&gt;Testes Unitários com TDD&lt;/a&gt;, Pablo Rodrigo Darde.&lt;/p&gt;

&lt;p&gt;Livro: Código Limpo, Robert C. Martin&lt;/p&gt;

</description>
      <category>braziliandevs</category>
      <category>testing</category>
      <category>womenintech</category>
      <category>tdd</category>
    </item>
    <item>
      <title>Test doubles</title>
      <dc:creator>Thalita Marra</dc:creator>
      <pubDate>Mon, 07 Jun 2021 17:48:59 +0000</pubDate>
      <link>https://forem.com/thalimarra/testes-de-software-test-doubles-56af</link>
      <guid>https://forem.com/thalimarra/testes-de-software-test-doubles-56af</guid>
      <description>&lt;ul&gt;
&lt;li&gt;Recorrendo a Test Doubles&lt;/li&gt;
&lt;li&gt;Quais Test Doubles existem?&lt;/li&gt;
&lt;li&gt;Test Doubles e Refatoração&lt;/li&gt;
&lt;li&gt;Cuidado com o SUT&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Olá olá!&lt;/p&gt;

&lt;p&gt;Hoje eu quero falar de algo que me confundiu muito quando comecei a aplicar testes: como eu faço pra substituir coisas desnecessárias ao objetivo do teste? Quais conceitos preciso entender para escrever os testes de forma que meus pares também entendam?&lt;/p&gt;

&lt;p&gt;Imagine que você está desenvolvendo uma integração com algum meio de pagamento (PayPal, Mercado Pago, etc.) e precisa testar essa classe.&lt;/p&gt;

&lt;p&gt;Podemos criar os testes sem alterar nada no código e continuar chamando a integração. Fazer isso vem com vários problemas como criar uma dependência do nosso teste no serviço externo, aumentar o tempo de execução da rotina de testes, pode afetar algum limite de requisição que o serviço imponha, e por ai vai...&lt;/p&gt;

&lt;p&gt;Podemos criar nossos testes ignorando todas as etapas que utilizam o serviço externo, mas assim vamos acabar ignorando parte da lógica interna. Como testar se o banco de dados está sendo atualizado depois que o pagamento foi feito com sucesso? Como confirmar que os tratamentos de erro estão funcionando conforme o esperado?&lt;/p&gt;

&lt;h2&gt;
  
  
  Recorrendo a Test Doubles &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;O termo &lt;em&gt;Test Doubles&lt;/em&gt; foi descrito no livro &lt;em&gt;XUnit Test Patterns: Refactoring Test Code&lt;/em&gt;, de Gerard Meszaros e &lt;strong&gt;representa qualquer objeto que simula um objeto real para fins de teste&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Quando escrevemos nossos testes e nos deparamos com casos onde não podemos usar um componente real ou casos onde não seria prático usá-lo, podemos substituí-lo por um &lt;em&gt;Test Double&lt;/em&gt;. Os &lt;em&gt;test doubles&lt;/em&gt; não precisam ser exatamente como o componente real, precisam apenas se comportar de tal forma que o sistema sobre teste (&lt;em&gt;System Under Test&lt;/em&gt; ou SUT) pense que ele é real.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vamos para um exemplo prático?&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Precisamos fazer um sistema de assinatura que pode ter vários meios de pagamento. &lt;/p&gt;

&lt;p&gt;Uma forma de executar isso é criando uma classe de integração para cada meio de pagamento e padronizá-las através de uma interface, chamada &lt;code&gt;Gateway&lt;/code&gt;, para garantir que todas as classes respeitem o mesmo contrato.&lt;/p&gt;

&lt;p&gt;Esse contrato é dividido em três funções: &lt;code&gt;register&lt;/code&gt;, que cria um novo registro do nosso usuário na plataforma de pagamento, &lt;code&gt;activate&lt;/code&gt;, que ativa a assinatura, e &lt;code&gt;deactivate&lt;/code&gt;, que inativa a assinatura quando o usuário quiser cancelar seu plano:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Gateway&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;activate&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;deactivate&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com a interface &lt;code&gt;Gateway&lt;/code&gt; padronizamos como será feita a integração com o meio de pagamento, mas agora precisamos resolver as nossas regras de negócio.&lt;/p&gt;

&lt;p&gt;Para isso temos a classe &lt;code&gt;Subscription&lt;/code&gt; que será responsável por chamar a integração, o gerenciamento do usuário e enviar um email de confirmação da assinatura. Isso tudo será feito dentro de uma função chamada &lt;code&gt;create&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Subscription&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;Gateway&lt;/span&gt; &lt;span class="nv"&gt;$gateway&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;Mailer&lt;/span&gt; &lt;span class="nv"&gt;$mailer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Gateway&lt;/span&gt; &lt;span class="nv"&gt;$gateway&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Mailer&lt;/span&gt; &lt;span class="nv"&gt;$mailer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;gateway&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$gateway&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;mailer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$mailer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;User&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;gateway&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$receipt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;gateway&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;activate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$receipt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;mailer&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'Your receipt number is: '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$receipt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Temos também a classe &lt;code&gt;User&lt;/code&gt; com todos os métodos responsáveis por gerir os dados do usuário do nosso sistema. Essa classe possui o método &lt;code&gt;subscribe&lt;/code&gt;, que é responsável por vincular o usuário ao ponteiro do meio de pagamento, e o método &lt;code&gt;isSubscribed&lt;/code&gt;, que retorna se aquele objeto possui ou não uma assinatura vinculada.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;?string&lt;/span&gt; &lt;span class="nv"&gt;$subscription&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$subscriptionId&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$subscriptionId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;isSubscribed&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;is_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Por fim, criamos uma integração com algum serviço de envio de email chamada &lt;code&gt;Mailer&lt;/code&gt; para enviar uma mensagem ao usuário:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Mailer&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;User&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$message&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// logica&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pronto, esse é o nosso SUT, o sistema que vamos testar. E sem mais delongas, vamos aos &lt;em&gt;test doubles&lt;/em&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Quais Test Doubles existem? &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Segundo Gerard Meszaros eles podem ser divididos em cinco categorias: Fakes, Dummies, Stubs, Mocks e Spies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fake
&lt;/h3&gt;

&lt;p&gt;Fakes são objetos com implementações funcionais que normalmente usam atalhos para executar ações.&lt;/p&gt;

&lt;p&gt;Para não precisar usar a implementação de produção no nosso teste, podemos criar uma classe Fake que respeita o mesmo contrato da classe de produção e usar ela nos nossos testes. Para o nosso exemplo poderia ser uma classe assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Tests&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Gateway&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GatewayFake&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Gateway&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;activate&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;'some-uuid'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;deactivate&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ela usa a mesma interface de produção (&lt;code&gt;Gateway&lt;/code&gt;), possui os mesmos métodos que são chamados pela classe &lt;code&gt;Subscription&lt;/code&gt;, mas não executam nenhuma ação real, possui apenas o suficiente para rodarmos nossos testes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dummy
&lt;/h3&gt;

&lt;p&gt;Dummy é um objeto sem nenhuma funcionalidade específica; é usado apenas para preencher parâmetros.&lt;/p&gt;

&lt;p&gt;Vamos para o primeiro caso de teste: precisamos validar se o usuário foi atualizado após a ativação da assinatura.&lt;/p&gt;

&lt;p&gt;Usando a biblioteca PHPUnit é possível escrever o teste da seguinte forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testValidaUsuarioComAssinatura&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$gatewayFake&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GatewayFake&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nv"&gt;$mailerDummy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createMock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Mailer&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Subscription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$gatewayFake&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$mailerDummy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Maria'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertFalse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isSubscribed&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="nv"&gt;$subscription&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isSubscribed&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para não chamar a integração com o meio de pagamento usamos a classe &lt;code&gt;GatewayFake&lt;/code&gt; que criamos anteriormente. Como também não precisamos validar nenhum comportamento do envio de email substituímos a classe &lt;code&gt;Mailer&lt;/code&gt; por um Dummy criado através do PHPUnit apenas para preencher os requisitos da construção da classe &lt;code&gt;Subscription&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;O uso de Fake e Dummy aqui foi apenas uma forma de exemplificar esses dois conceitos. Poderíamos criar um Fake para o envio de email ou um Dummy para a integração com o meio de pagamentos sem problema algum.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Note que o nome da função chamada para criar o Dummy é &lt;code&gt;createMock(...)&lt;/code&gt;. Não é incomum o uso do termo Mock como sinônimo de qualquer um dos outros &lt;em&gt;test doubles&lt;/em&gt; mas ele também tem outra definição, que veremos logo a seguir.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Stub
&lt;/h3&gt;

&lt;p&gt;Stubs são objetos que usamos para simular &lt;strong&gt;interações de chegada&lt;/strong&gt; de alguma dependência externa ao SUT. Eles são usados apenas para fornecer uma resposta programada para aquele teste.&lt;/p&gt;

&lt;p&gt;No nosso exemplo a classe de &lt;code&gt;Subscription&lt;/code&gt; solicita a ativação da assinatura através da função &lt;code&gt;activate&lt;/code&gt; e atualiza o UUID que retornou da integração nos dados do usuário interno.&lt;/p&gt;

&lt;p&gt;Para garantir a integridade dos dados do nosso usuário precisamos ter certeza que o valor retornado pela função &lt;code&gt;activate&lt;/code&gt; é o mesmo que está sendo salvo no usuário:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testValidaValorCorretoAssinatura&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$gatewayStub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createStub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Gateway&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$gatewayStub&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'activate'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;willReturn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'some-uuid'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$mailerDummy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createMock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Mailer&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Subscription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$gatewayStub&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$mailerDummy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Maria'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// valida que o usuario foi criado sem assinatura&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertNull&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$subscription&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// valida que o valor salvo no banco é o mesmo retornado pela integração&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'some-uuid'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para validar esse cenário precisamos que o método &lt;code&gt;activate&lt;/code&gt; retorne uma string correspondente ao UUID externo, portanto criamos um Stub para simular essa &lt;strong&gt;interação de chegada&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Como não precisamos validar o envio de email, permanecemos com o Dummy para a classe &lt;code&gt;Mailer&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mock
&lt;/h3&gt;

&lt;p&gt;Mocks, por sua vez, são objetos que usamos para simular &lt;strong&gt;interações de saída&lt;/strong&gt;. Eles possuem expectativas sobre seu comportamento, ou seja, verificam se um ou mais métodos foram chamados, a ordem e quantidade de vezes que foram chamados, etc, lançando exceções quando o teste não se comporta conforme o esperado.&lt;/p&gt;

&lt;p&gt;Vamos testar se o SUT está enviando o email quando a assinatura é criada:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testValidaEnvioDeEmail&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;expectNotToPerformAssertions&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Maria'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$gatewayStub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createStub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Gateway&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$gatewayStub&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'activate'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;willReturn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'some-uuid'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$mailerMock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Mockery&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;mock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Mailer&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$mailerMock&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;shouldReceive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'send'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;once&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;withArgs&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Your receipt number is: some-uuid'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="nv"&gt;$subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Subscription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$gatewayStub&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$mailerMock&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$subscription&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Aqui acabei usando a biblioteca Mockery junto ao PHPUnit para melhorar a legibilidade do código.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Podemos ver no teste acima que logo no começo foi explicito que não haveria nenhum afirmação (&lt;code&gt;assert&lt;/code&gt;). Ao invés disso apenas validamos as expectativas da &lt;strong&gt;interação de saída&lt;/strong&gt; do SUT em relação ao serviço externo.&lt;/p&gt;

&lt;p&gt;Ou seja, descrevemos nossa expectativa (&lt;code&gt;shouldReceive()&lt;/code&gt;) que o serviço de envio de email chamaria o método &lt;code&gt;send&lt;/code&gt;, que essa chamada aconteceria apenas uma vez (&lt;code&gt;once()&lt;/code&gt;) e que os argumentos passados para o método (&lt;code&gt;withArgs()&lt;/code&gt;) seriam o usuário e aquela exata mensagem.&lt;/p&gt;

&lt;p&gt;Caso a mensagem ou o objeto &lt;code&gt;$user&lt;/code&gt; estejam diferentes do definido no teste, o mesmo iria falhar.&lt;/p&gt;

&lt;h3&gt;
  
  
  Spy
&lt;/h3&gt;

&lt;p&gt;Spy pode ser definido como uma combinação do Stub com o Mock. Spies validam informações com base em como foram chamados e também permitem testar as interações tanto de chegada quanto de saída.&lt;/p&gt;

&lt;p&gt;Diferem dos Stubs e Mocks no fato de que os Spies registram qualquer interação entre ele e o SUT e nos permitem fazer afirmações contra essas interações &lt;strong&gt;após o fato&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Usaremos um Spy para garantir que a assinatura foi ativada e não houve nenhuma chamada do fluxo de inativação:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testConfirmaAssinaturaAtiva&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;expectNotToPerformAssertions&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nv"&gt;$gatewaySpy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Mockery&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;spy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Gateway&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$mailerDummy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createMock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Mailer&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Subscription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$gatewaySpy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$mailerDummy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$subscription&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Maria'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="nv"&gt;$gatewaySpy&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;shouldHaveReceived&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'activate'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$gatewaySpy&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;shouldNotHaveReceived&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'deactivate'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Logo no começo foi definido que não haveria nenhuma afirmação, já que não faz parte do objetivo do teste. E como não precisamos testar nada do fluxo de envio de email, voltamos a usar um Dummy para a classe &lt;code&gt;Mailer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;O Spy que substituiu o gateway de pagamento verifica depois de todo o fluxo executado quais funções foram chamadas e quais não foram, validando que houve uma chamada para a função &lt;code&gt;activate&lt;/code&gt; e nenhuma para a função &lt;code&gt;deactivate&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test Doubles e Refatoração &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Usar um &lt;em&gt;test double&lt;/em&gt; requer que saibamos de um certo nível de detalhe sobre a implementação do que estamos testando. &lt;/p&gt;

&lt;p&gt;Nos cenários que testamos aqui foi preciso saber, por exemplo, que para um usuário ser considerado assinante ele deveria salvar o UUID que retornou da integração com o meio de pagamento. O teste fica vinculado à implementação.&lt;/p&gt;

&lt;p&gt;Quando refatoramos o código é possível que o teste também precise ser refatorado. Então cabe ao desenvolvedor saber quando é necessário usar o &lt;em&gt;test double&lt;/em&gt; ou quando podemos deixar para que a classe resolva o que precisa ser resolvido usando objetos reais.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cuidado com o SUT &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Quando executamos os testes estamos validando algum aspécto do SUT.&lt;/p&gt;

&lt;p&gt;Os &lt;em&gt;test doubles&lt;/em&gt; estão ai para nos ajudar a lidar com dependências de um ou mais componentes, isolar o objeto de teste, simplificar comportamentos e nos dar mais controle sobre a situação. &lt;/p&gt;

&lt;p&gt;Às vezes se torna tentador criar um &lt;em&gt;test double&lt;/em&gt; para substituir parte do SUT e essa é uma ideia ruim. &lt;/p&gt;

&lt;p&gt;Se você tiver vontade de substituir o comportamento de determinada função da classe que está testando, por exemplo, veja como um indicativo de que aquele código possui uma complexidade alta e talvez faça sentido ser encapsulada em uma classe própria.&lt;/p&gt;




&lt;p&gt;Bom, esse post acabou ficando maior do que eu imaginei, então vou parar por aqui.&lt;/p&gt;

&lt;p&gt;Caso tenha ficado alguma dúvida pode deixar nos comentários que eu respondo assim que possível. E vou deixar aqui também alguns recursos que me ajudaram enquanto montava esse post:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/thmarra/example-test-doubles"&gt;Repositório com o código&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="%5Bhttps://martinfowler.com/bliki/TestDouble.html%5D(https://martinfowler.com/bliki/TestDouble.html)"&gt;Test Double - Martin Fowler&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="%5Bhttps://medium.com/concretebr/test-doubles-swift-cd43372eb45e%5D(https://medium.com/concretebr/test-doubles-swift-cd43372eb45e)"&gt;Test Doubles Swift - Matheus de Vasconcelos&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="%5Bhttps://medium.com/rd-shipit/test-doubles-mocks-stubs-fakes-spies-e-dummies-a5cdafcd0daf%5D(https://medium.com/rd-shipit/test-doubles-mocks-stubs-fakes-spies-e-dummies-a5cdafcd0daf)"&gt;Test Doubles - Pablo Rodrigo Darde&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="%5Bhttps://thoughtbot.com/blog/don-t-stub-the-system-under-test%5D(https://thoughtbot.com/blog/don-t-stub-the-system-under-test)"&gt;Don't Stub the System Under Test - Joe Ferris&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="%5Bhttps://laracasts.com/series/php-testing-jargon%5D(https://laracasts.com/series/php-testing-jargon)"&gt;PHP Testing Jargon - Laracasts&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Até a próxima!&lt;/p&gt;

</description>
      <category>womenintech</category>
      <category>testing</category>
      <category>braziliandevs</category>
      <category>php</category>
    </item>
    <item>
      <title>O que testar em um software?</title>
      <dc:creator>Thalita Marra</dc:creator>
      <pubDate>Mon, 24 May 2021 21:18:03 +0000</pubDate>
      <link>https://forem.com/thalimarra/testes-de-software-parte-2-li9</link>
      <guid>https://forem.com/thalimarra/testes-de-software-parte-2-li9</guid>
      <description>&lt;p&gt;Olá olá! Bora continuar o papo sobre testes? &lt;/p&gt;

&lt;p&gt;No &lt;a href="https://dev.to/thalimarra/testes-de-software-parte-1-3330"&gt;post anterior&lt;/a&gt; falei sobre o que são testes de software, quais as técnicas que podemos empregar na criação e execução dos mesmos e também quais suas classificações em relação à etapa do ciclo de vida do software.&lt;/p&gt;

&lt;p&gt;Ou seja, já vimos o como e o quando testar, mas falta uma pergunta muito importante...&lt;/p&gt;

&lt;h2&gt;
  
  
  O que testar?
&lt;/h2&gt;

&lt;p&gt;Sabemos que um &lt;strong&gt;teste de sistema&lt;/strong&gt;, por exemplo, procura confirmar se o software desenvolvido está funcionando de acordo com os contratos definidos, mas o que valida se o contrato foi cumprido? Se eu informo um valor X e recebo Y de resposta? Se o tempo de execução até eu receber a resposta foi abaixo de N segundos? Existem vários aspectos do software que podem ser testados de acordo com as necessidades do projeto.&lt;/p&gt;

&lt;p&gt;Dessa forma, podemos classificar os testes de acordo com seu foco (aquilo que pretendem validar):&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;Teste de funcionalidade:&lt;/strong&gt; tem como objetivo validar se as funções do sistema são executadas corretamente. Também checa se a aplicação envia resultados relevantes para o contexto do sistema, como por exemplo tratamentos de erros padronizados e suficientemente informativos.&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;Teste de usabilidade:&lt;/strong&gt; foca na experiência do usuário ao utilizar o sistema. Observa e analisa usuários reais utilizando o produto (que pode ser um site, um aplicativo, etc). É bastante comum o uso de protótipos para a execução desse teste.&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;Teste de segurança:&lt;/strong&gt; valida a proteção do sistema contra acessos não autorizados e invasões através da checagem de perfis de acesso, confirmação da codificação de dados quando necessário, etc. São executadas uma série de explorações no software buscando identificar e corrigir a maior quantidade possível de vulnerabilidades.&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;Teste de portabilidade:&lt;/strong&gt; atesta o funcionamento do sistema em diferentes plataformas e dispositivos nas quais o sistema foi proposto a funcionar. Por exemplo: valida se um site funciona em múltiplos navegadores, um aplicativo funciona em múltiplos sistemas operacionais, etc.&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;Teste de desempenho:&lt;/strong&gt; busca confirmar se o tempo de resposta de determinado software está dentro do esperado.&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;Teste de stress:&lt;/strong&gt; valida o comportamento do sistema em condições extremas para procurar e corrigir possíveis falhas e identificar melhorias de desempenho o quanto antes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Apesar de ser bem parecido com um teste de desempenho, o teste de stress leva o sistema ao limite, testando seu funcionamento em um ambiente com memória insuficiente, recursos compartilhados limitados, serviços indisponíveis, etc. O teste de desempenho já valida o sistema em um ambiente mais próximo da realidade.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Essas são os aspectos mais comuns a serem testados mas não são os únicos. Podemos testar coisas como concorrência, recuperabilidade do sistema, compatibilidade, por aí vai. Cada software pode ter alguma peculiaridade que precisa de garantia e para isso pode ser necessário testar coisas mais especificas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Boas práticas
&lt;/h2&gt;

&lt;p&gt;Por fim, mas não menos importante, vou deixar aqui algumas práticas que podem ajudar na definição, criação e execução dos testes:&lt;/p&gt;

&lt;p&gt;• Idealmente, a pessoa que especifica os casos de testes não deve ser a mesma que participa da codificação. Se eu criei o login de um sistema e eu mesma vou testá-lo, é mais fácil me prender apenas ao que já presenciei enquanto codificava, ou seja, meus testes estarão enviesados.&lt;/p&gt;

&lt;p&gt;• Faça uma boa seleção de cenários de teste. Considere o tempo disponível para a execução dos testes, a maturidade técnica dos envolvidos, a relevância das funcionalidades. E lembre-se que &lt;strong&gt;o que não está especificado não será validado&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;• Quando necessário podemos explorar casos de testes além dos já definidos, aumentando ainda mais a cobertura do código.&lt;/p&gt;

&lt;p&gt;• Não ignore cenários aparentemente inocentes.&lt;/p&gt;

&lt;p&gt;• É bem possível encontrar falhas no sistema durante a execução dos testes. Quando isso acontecer, detalhe as falhas da melhor forma possível, assim facilita o trabalho de quem for corrigir e de quem for testar o sistema mais a frente.&lt;/p&gt;

&lt;p&gt;• Inclusive, teste novamente os cenários com falhas depois das devidas correções!&lt;/p&gt;

&lt;p&gt;• Ao reportar uma falha, busque padrões. Por exemplo: todos os produtos da categoria X apresentam erro quando adicionados ao carrinho de compras.&lt;/p&gt;

&lt;p&gt;• Teste sempre os valores limites, há uma grande chance de erros estarem ali. Por exemplo: um sistema permite cadastro apenas de pessoas maiores de 18 anos e menores que 70 anos, então teste também as idades 16, 18, 70, 71... Testar os limites significa testar valores positivos e negativos, tamanhos de arquivos, etc.&lt;/p&gt;

&lt;p&gt;• Confira se as informações retornadas pelo sistema estão coerentes, como mensagens de erros e sucesso, textos explicativos, etc.&lt;/p&gt;

&lt;p&gt;• Por fim, pense como um usuário pensaria.&lt;/p&gt;




&lt;p&gt;Então é isso, pessoal. Essas foram as minhas anotações das leituras sobre testes e do curso &lt;a href="https://www.udemy.com/course/teste-software-completo-testes-automaticos/"&gt;Teste de Software&lt;/a&gt;. Espero que ajude vocês também. Confesso que não fiz o curso todo porque queria estudar apenas a teoria inicial, mas super indico o material para quem ainda ficou meio perdido no assunto. E qualquer coisa pode deixar aqui nos comentários que vou respondendo assim que ver.&lt;/p&gt;

&lt;p&gt;Até a próxima!&lt;/p&gt;

</description>
      <category>testing</category>
      <category>womenintech</category>
      <category>100daysofcode</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Como e quando testar um software?</title>
      <dc:creator>Thalita Marra</dc:creator>
      <pubDate>Mon, 17 May 2021 12:32:41 +0000</pubDate>
      <link>https://forem.com/thalimarra/testes-de-software-parte-1-3330</link>
      <guid>https://forem.com/thalimarra/testes-de-software-parte-1-3330</guid>
      <description>&lt;p&gt;Desenvolver um software não é uma tarefa lá muito simples. Envolve entender bem o que precisa ser feito, o objetivo da coisa e até os pontos sensíveis da ideia. Mas uma vez que o código da aplicação está pronto, acabou. Certo? Bem… Uma parte importantíssima do processo de desenvolvimento de uma aplicação é testá-la e garantir que tudo está funcionando conforme o esperado.&lt;/p&gt;

&lt;p&gt;Para quem está codando se torna muito fácil enxergar apenas o “caminho feliz” das funcionalidades desenvolvidas e deixar passar alguns bugs despercebidos no caminho.&lt;/p&gt;

&lt;p&gt;O teste de software serve justamente para tentar encontrar e resolver (até prevenir) as falhas que um programa possa apresentar para que, quando estiver disponível para o público, o comportamento do sistema seja o mais correto possível.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tipos de testes
&lt;/h2&gt;

&lt;p&gt;Os testes podem ser estáticos ou dinâmicos. Um &lt;strong&gt;teste estático&lt;/strong&gt; é feito quando o sistema não está em execução. Esses testes vão desde uma análise visual do código buscando variáveis ou classes declaradas incorretamente até a análise do código por um software terceiro que procura por diversos &lt;em&gt;code smells&lt;/em&gt;, por exemplo.&lt;/p&gt;

&lt;p&gt;Um &lt;strong&gt;teste dinâmico&lt;/strong&gt; é aquele que precisa que o sistema esteja em execução para que seja testado, onde se envia uma entrada e se espera determinada saída; são testes que validam o funcionamento do sistema.&lt;/p&gt;

&lt;p&gt;Assim como separamos o teste de acordo com o estado da aplicação, também podemos separá-los de acordo à disponibilidade de acesso ao código. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testes de caixa aberta&lt;/strong&gt; (ou caixa branca) são aqueles feitos quando temos acesso ao código fonte e &lt;strong&gt;testes de caixa fechada&lt;/strong&gt; (ou caixa preta) quando não possuímos acesso.&lt;/p&gt;

&lt;p&gt;Por fim, os testes podem ser manuais ou automatizados. Os &lt;strong&gt;testes manuais&lt;/strong&gt; são mais flexíveis e podem explorar mais casos além dos que foram planejados, porém são mais lentos e possuem um alto custo de execução. &lt;/p&gt;

&lt;p&gt;Em contraposto os &lt;strong&gt;testes automatizados&lt;/strong&gt; são mais rápidos e de mais fácil execução, possuindo um alto custo de criação e validando apenas os cenários especificados.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testes por nível
&lt;/h2&gt;

&lt;p&gt;Um software pode possuir diversos testes que irão envolver níveis diferentes de seus componentes, indo desde pequenas unidades de código até o sistema como um todo. Esses testes são desenvolvidos em função do estágio do ciclo de vida do software e são feitos para validar o desempenho e comportamento do software em diferentes estágios.&lt;/p&gt;

&lt;p&gt;Antes de falar continuar, vamos repassar brevemente quais são os estágios do ciclo de vida de um software. De forma bem simples, temos:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff17ihy2jcbmcrlb4z43e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff17ihy2jcbmcrlb4z43e.png" alt="Ciclo de vida do software: levantamento de requisitos, projeto do software, programação, homologação e manutenção do sistema"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Os seguintes testes validam diferentes níveis do sistema e são feitos de acordo com o estágio do ciclo de vida:&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;Teste de unidade:&lt;/strong&gt; procuram falhas em um único componente do sistema, funcionando independente do todo. Geralmente é o primeiro teste feito durante o desenvolvimento do sistema. São escritos por programadores e executados de forma automatizada.&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;Teste de integração:&lt;/strong&gt; busca validar a comunicação entre componentes do sistema em uma etapa mais intermediária do desenvolvimento, quando já existem componentes que interagem entre si. Também são escritos por programadores e executados de forma automatizada.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Exemplo: classe Assinatura gere o plano de assinatura de um cliente e ela interage com a classe Boleto, que é responsável por emitir o boleto daquela assinatura.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;• &lt;strong&gt;Teste de sistema:&lt;/strong&gt; executa o sistema sob ponto de vista do usuário final, buscando falhas em relação aos objetivos originais. Pode ser executado através do navegador, um client rest ou qualquer plataforma que o usuário irá usar. Costuma ser feito por uma equipe de testes após a conclusão do desenvolvimento e auxiliado por um documento descrevendo todos os cenários de testes correspondentes aos requisitos do sistema.&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;Teste de aceitação:&lt;/strong&gt; bastante similar ao teste anterior, o teste de aceitação também executa o sistema sob a ótica do usuário final visando confirmar se o objetivo original foi atingido, mas ao invés de serem realizados por uma equipe especializada são planejados e executados por um grupo restrito de usuários finais do sistema. Esse teste que determina se o cliente aceita ou não o sistema que foi desenvolvido.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Enquanto no teste de sistema uma equipe especializada valida se os contratos (requisitos) foram cumpridos, no teste de aceitação o cliente valida o desenvolvimento e confirma se aceita ou não o resultado apresentado.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;• &lt;strong&gt;Teste de manutenção:&lt;/strong&gt; também chamado de teste de regressão, procura garantir que as alterações em um código não afetam outros componentes que foram desenvolvidos em etapas anteriores do ciclo de vida. Após uma correção de bug ou alteração de um escopo, por exemplo, esses testes validam se todos os componentes que já estavam prontos permaneceram com o comportamento adequado. Podem envolver qualquer nível do sistema (unitário, interface, o sistema como um todo, etc).&lt;/p&gt;

&lt;p&gt;Se juntarmos os testes com o ciclo de vida do produto temos algo assim:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl405kfww6s7awaivf5gp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl405kfww6s7awaivf5gp.png" alt="O planejamento dos testes começa já no levantamento de requisito. Os testes unitários e de integração são feitos durante a etapa de programação, o teste de sistema e aceitação são feitos durante a etapa de homologação e os testes de manutenção são feitos durante a manutenção"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Essa sequência é um compilado das minhas anotações de estudos sobre testes de software baseados em diversas leituras e, principalmente, no curso &lt;a href="https://www.udemy.com/course/teste-software-completo-testes-automaticos/" rel="noopener noreferrer"&gt;Teste de Software&lt;/a&gt; disponível na Udemy. E como ainda temos muito pano pra manga sobre esse assunto, vou deixar mais um pouquinho pra uma parte 2. &lt;/p&gt;

&lt;p&gt;Nos vemos logo mais!&lt;/p&gt;

</description>
      <category>testing</category>
      <category>womenintech</category>
      <category>100daysofcode</category>
      <category>braziliandevs</category>
    </item>
  </channel>
</rss>
