<?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>DEV Community: Ágatha</title>
    <description>The latest articles on DEV Community by Ágatha (@htamagnus).</description>
    <link>https://dev.to/htamagnus</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%2F1183640%2Fae84ab89-2fac-484d-a38f-9f686ba7c29a.jpeg</url>
      <title>DEV Community: Ágatha</title>
      <link>https://dev.to/htamagnus</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/htamagnus"/>
    <language>en</language>
    <item>
      <title>FIRST Principles and Test Smells 🚀</title>
      <dc:creator>Ágatha</dc:creator>
      <pubDate>Sat, 04 May 2024 18:53:35 +0000</pubDate>
      <link>https://dev.to/htamagnus/first-principles-and-test-smells-54c6</link>
      <guid>https://dev.to/htamagnus/first-principles-and-test-smells-54c6</guid>
      <description>&lt;p&gt;When it comes to writing high-quality unit tests, there are some basic principles, grouped under the acronym &lt;strong&gt;FIRST&lt;/strong&gt;, that can be quite helpful.&lt;/p&gt;




&lt;h2&gt;
  
  
  Fast ⚡
&lt;/h2&gt;

&lt;p&gt;Unit tests should always be fast. The idea is that you can run them all the time, without having to wait. If you need a coffee while your tests run, they probably aren't fast enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  Independent 🧍
&lt;/h2&gt;

&lt;p&gt;Each unit test should be able to stand on its own. It doesn't matter in what order you decide to run them; they should not depend on each other.&lt;/p&gt;

&lt;h2&gt;
  
  
  Repeatable 🔁
&lt;/h2&gt;

&lt;p&gt;If you run the same test multiple times, the outcome should always be the same: either the test always passes or always fails. Tests that sometimes pass and sometimes fail without any apparent reason are called "flaky" or erratic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Self-checking ✅
&lt;/h2&gt;

&lt;p&gt;Once the test execution is complete, the result should be self-explanatory (passed/failed). This way, the outcome can be quickly verified and interpreted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Timely 🕰️
&lt;/h2&gt;

&lt;p&gt;It's a good idea to write your unit tests as early as possible in your development process. Many people even prefer to write the tests before the code they will test; this helps ensure that your code will do exactly what you expect from the start.&lt;/p&gt;




&lt;h2&gt;
  
  
  Test Smells 🐟👃
&lt;/h2&gt;

&lt;p&gt;Some signs in your test code may indicate that something could be improved. These signs are called "Test Smells":&lt;/p&gt;

&lt;h2&gt;
  
  
  Obscure Test 🌫️🤔
&lt;/h2&gt;

&lt;p&gt;In code, an "Obscure Test" is complicated, long, and difficult to understand. Tests should be simple and straightforward so that anyone can understand what is being tested and why. It is important to have a clear and easy-to-understand logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test with Conditional Logic ➰❓
&lt;/h2&gt;

&lt;p&gt;A test with many "ifs" and "elses" makes it difficult to understand exactly what is being tested and under what conditions. Ideally, unit tests should be linear; conditional logic in tests hampers understanding.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Duplication in Tests 📄🚫
&lt;/h2&gt;

&lt;p&gt;If you have repeated code in several tests, there might be a more efficient way to organize this.&lt;/p&gt;

&lt;p&gt;Test Smells are like a signal that maybe you can simplify or better organize your tests. It's not that you can never have an "if" in a test or a slightly longer test, but it's a reminder to stop and think: "Is there a simpler way to do this?”&lt;/p&gt;




&lt;p&gt;Most of this content came from the book "Modern Software Engineering", written by Marco Tulio Valente. This book is a treasure trove of tips on how to create tests the right way, using the latest and most efficient in the programming world. However, the only difference is that the book is in Java and here I adapted it to use JavaScript.&lt;/p&gt;




</description>
      <category>testing</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Testes de Sistema 🌐</title>
      <dc:creator>Ágatha</dc:creator>
      <pubDate>Sun, 07 Apr 2024 18:56:41 +0000</pubDate>
      <link>https://dev.to/htamagnus/testes-de-sistema-494i</link>
      <guid>https://dev.to/htamagnus/testes-de-sistema-494i</guid>
      <description>&lt;p&gt;Testes de sistema são uma &lt;strong&gt;simulação completa&lt;/strong&gt; de como um &lt;strong&gt;usuário real&lt;/strong&gt; interage com o aplicativo, de ponta a ponta. São os testes mais abrangentes e, por isso, geralmente os mais &lt;strong&gt;caros&lt;/strong&gt; e os que levam mais &lt;strong&gt;tempo&lt;/strong&gt; para serem executados.&lt;/p&gt;




&lt;p&gt;Para automatizar testes de sistemas Web em JavaScript, você pode usar ferramentas como &lt;a href="https://www.selenium.dev/"&gt;Selenium&lt;/a&gt; ou alternativas modernas como &lt;a href="https://www.cypress.io/"&gt;Cypress&lt;/a&gt; ou &lt;a href="https://pptr.dev/"&gt;Puppeteer&lt;/a&gt;. Essas ferramentas permitem que você escreva scripts de teste que interagem com o navegador, assim como um usuário real faria.&lt;/p&gt;




&lt;h2&gt;
  
  
  Exemplo: Teste de Sistemas Web 💻
&lt;/h2&gt;

&lt;p&gt;Essa é a forma em como você poderia escrever um teste para uma pesquisa no Google usando Puppeteer, que é uma biblioteca Node.js para controlar navegadores Headless Chrome ou Chromium:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// googleSearch.test.js
const puppeteer = require('puppeteer');

describe('Google Search', () =&amp;gt; {
  it('should search for "software"', async () =&amp;gt; {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto('http://www.google.com');

    await page.type('input[name=q]', 'software');
    await page.keyboard.press('Enter');

    await page.waitForSelector('h3'); // Espera pelo carregamento dos resultados

    const pageTitle = await page.title();
    console.log(`Page title is: ${pageTitle}`);

    await browser.close();

    expect(pageTitle).toMatch('software - Google Search');
  }, 16000); // Aumentar o timeout para testes que podem levar mais tempo
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neste script, Puppeteer abre o navegador, vai para o Google, digita a palavra "software" na pesquisa, pressiona Enter e espera pelos resultados da pesquisa.&lt;/p&gt;




&lt;h2&gt;
  
  
  Exemplo: Teste de um Compilador 🛠️
&lt;/h2&gt;

&lt;p&gt;Se você estivesse testando um compilador em JavaScript, o teste poderia ser mais direto porque você está apenas lidando com arquivos de entrada e saída, não uma interface de usuário.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// compiler.test.js
const { compile } = require('./compiler');
const fs = require('fs');

describe('Compiler Tests', () =&amp;gt; {
  it('should compile program correctly', async () =&amp;gt; {
    const inputProgram = 'path/to/program.x';
    const expectedOutput = 'expected program output';

    await compile(inputProgram);

    const output = fs.readFileSync('path/to/output', 'utf8');
    expect(output).toBe(expectedOutput);
  });
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aqui, o &lt;code&gt;compile&lt;/code&gt; é uma função que você escreveria para pegar o caminho para um arquivo de programa, compilar esse programa e, em seguida, você verificaria a saída contra o esperado.&lt;/p&gt;




&lt;h2&gt;
  
  
  Considerações 🤔
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Testes de sistema devem refletir cenários de uso reais;&lt;/li&gt;
&lt;li&gt;Mudanças na interface do usuário ou nos sistemas externos podem quebrar seus testes, então eles precisam ser mantidos atualizados;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;A maior parte desse conteúdo veio do livro "Engenharia de Software Moderna", escrito por Marco Tulio Valente. Esse livro é um tesouro cheio de dicas sobre como criar testes do jeito certo, usando o que tem de mais novo e eficiente no mundo da programação. Entretanto, a única diferença, é que o livro é em Java e aqui eu adaptei para utilizar Javascript.&lt;/p&gt;




</description>
      <category>javascript</category>
    </item>
    <item>
      <title>Testes de Integração 🔗</title>
      <dc:creator>Ágatha</dc:creator>
      <pubDate>Sun, 07 Apr 2024 18:43:47 +0000</pubDate>
      <link>https://dev.to/htamagnus/testes-de-integracao-4j91</link>
      <guid>https://dev.to/htamagnus/testes-de-integracao-4j91</guid>
      <description>&lt;p&gt;O objetivo principal dos &lt;strong&gt;testes de integração&lt;/strong&gt; é ter uma maior assertividade e conseguir interagir com o sistema real. Eles ajudam a garantir que as diversas partes do seu sistema como módulos individuais, serviços ou funções trabalhem juntas como esperado.&lt;/p&gt;

&lt;p&gt;Ao invés de testar partes isoladas do código (como funções individuais ou classes), é testado como diferentes partes funcionam juntas. Isso inclui &lt;strong&gt;interações&lt;/strong&gt; com bancos de dados, APIs externas ou qualquer outro serviço que seu aplicativo use.&lt;/p&gt;

&lt;p&gt;O &lt;strong&gt;objetivo&lt;/strong&gt; desses testes é garantir que todos os módulos ou serviços do seu aplicativo trabalhem junto quando combinados, detectando problemas que podem não ser visíveis em testes de unidade.&lt;/p&gt;




&lt;h2&gt;
  
  
  Exemplo: Agenda de Compromissos 📅
&lt;/h2&gt;

&lt;p&gt;Digamos que você está trabalhando em um sistema de agenda para gerenciar compromissos, e quer testar se a lógica de adicionar e listar compromissos está funcionando corretamente, incluindo a interação com um banco de dados real.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Agenda.js
class Agenda {
  constructor(database) {
    this.database = database;
  }

  addAppointment(appointment) {
    // Código para adicionar um compromisso ao banco de dados
  }

  listAppointments() {
    // Código para listar compromissos do banco de dados
  }
}

module.exports = Agenda;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em seguida, você escreve um teste de integração para verificar se a adição e listagem de compromissos estão funcionando como esperado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Agenda.test.js
const Agenda = require('./Agenda');
const Database = require('./Database'); // Uma classe que representa o seu banco de dados real

describe('Agenda Integration Test', () =&amp;gt; {
  it('should add and list appointments', async () =&amp;gt; {
    const database = new Database();
    const agenda = new Agenda(database);

    await agenda.addAppointment({ /* dados do compromisso */ });
    await agenda.addAppointment({ /* dados do compromisso */ });
    await agenda.addAppointment({ /* dados do compromisso */ });

    const appointments = await agenda.listAppointments();

    expect(appointments).toHaveLength(3);
  });
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Importante:&lt;/strong&gt; Nesse exemplo, você não usa mocks ou stubs, pois o objetivo é interagir com o sistema real, como um banco de dados. Assim, você terá uma instância real do banco de dados em seu teste, que deve estar configurado para um ambiente de teste, idealmente usando uma base de dados que possa ser limpa ou recriada antes de cada teste para garantir a consistência.&lt;/p&gt;




&lt;p&gt;Testes de integração geralmente são mais &lt;strong&gt;lentos&lt;/strong&gt; do que testes de unidade devido à sua complexidade e à necessidade de interagir com sistemas externos.&lt;/p&gt;

&lt;p&gt;Ao executar testes de integração, você está verificando não apenas a &lt;strong&gt;lógica do negócio&lt;/strong&gt;, mas também a &lt;strong&gt;integração&lt;/strong&gt; dessa lógica com outras partes do sistema, assegurando que o sistema como um todo funcione conforme o esperado.&lt;/p&gt;




&lt;p&gt;A maior parte desse conteúdo veio do livro "Engenharia de Software Moderna", escrito por Marco Tulio Valente. Esse livro é um tesouro cheio de dicas sobre como criar testes do jeito certo, usando o que tem de mais novo e eficiente no mundo da programação. Entretanto, a única diferença, é que o livro é em Java e aqui eu adaptei para utilizar Javascript.&lt;/p&gt;




</description>
      <category>javascript</category>
      <category>testing</category>
      <category>jest</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Desenvolvimento Dirigido por Testes (TDD) 🔁</title>
      <dc:creator>Ágatha</dc:creator>
      <pubDate>Sun, 07 Apr 2024 18:18:07 +0000</pubDate>
      <link>https://dev.to/htamagnus/desenvolvimento-dirigido-por-testes-tdd-ob8</link>
      <guid>https://dev.to/htamagnus/desenvolvimento-dirigido-por-testes-tdd-ob8</guid>
      <description>&lt;p&gt;Desenvolvimento Dirigido por Testes, ou TDD, é como fazer um plano &lt;strong&gt;antes&lt;/strong&gt; de começar uma viagem. Você &lt;strong&gt;decide&lt;/strong&gt; para onde quer ir (o que quer que seu código faça), &lt;strong&gt;verifica&lt;/strong&gt; se chegou lá (testa seu código), e se não, você &lt;strong&gt;descobre&lt;/strong&gt; um caminho (escreve o código para fazer o teste passar). Depois, você olha ao redor para ver se pode &lt;strong&gt;melhorar&lt;/strong&gt; algo na rota que escolheu (refatora o código).&lt;/p&gt;

&lt;p&gt;Com TDD, você começa escrevendo um teste para a funcionalidade que quer adicionar ou o bug que precisa consertar. No início, esse teste &lt;strong&gt;vai falhar&lt;/strong&gt; porque você ainda não escreveu o código que faz o que o teste espera, e isso é bom, por que significa que você tem uma meta clara.&lt;/p&gt;

&lt;p&gt;A próxima etapa é escrever o código que satisfaz esse teste. Inicialmente, você pode até fazer algo bem simples, só para ver o teste passar. Isso pode parecer um pouco ao contrário, mas tem um bom motivo: ajuda a &lt;strong&gt;garantir&lt;/strong&gt; que seu código só faz o que é realmente necessário e nada mais.&lt;/p&gt;

&lt;p&gt;Depois que o teste passa, você tem a oportunidade de &lt;strong&gt;melhorar&lt;/strong&gt; seu código, deixando-o mais limpo, organizado e eficiente. Isso é a &lt;strong&gt;refatoração&lt;/strong&gt;. Como você tem os testes, pode refazer seu código com segurança, sabendo que se algo quebrar, os testes vão te avisar.&lt;/p&gt;

&lt;p&gt;Por fim, TDD não é só sobre testar ou não esquecer de escrever testes. É uma forma de pensar sobre o design do seu software desde o início. Quando você escreve o &lt;strong&gt;teste primeiro&lt;/strong&gt;, está pensando na interface e na usabilidade do seu código antes mesmo de implementá-lo. Isso pode levar a um design melhor e mais limpo.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb71tevp9m9li33jjbbem.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb71tevp9m9li33jjbbem.png" alt="Image description" width="505" height="177"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Testes Falhando 🔴
&lt;/h2&gt;

&lt;p&gt;Você começa escrevendo um teste para a funcionalidade que quer criar, e esse teste vai falhar porque a funcionalidade ainda não existe. Isso é ótimo, porque agora você tem um claro ponto de partida e sabe exatamente o que seu código precisa alcançar. Aqui você também cria um esqueleto básico da sua classe ou função, só para o teste conseguir compilar.&lt;/p&gt;




&lt;h2&gt;
  
  
  Testes Passando ✅
&lt;/h2&gt;

&lt;p&gt;Agora é hora de fazer o teste passar, escrevendo código que atenda ao que o teste espera. No começo, o código pode ser relativamente &lt;strong&gt;bem simples&lt;/strong&gt;. Não precisa ser perfeito, só precisa ver o teste ficar verde, mostrando que a funcionalidade básica está funcionando.&lt;/p&gt;




&lt;h2&gt;
  
  
  Refatoração ♻️
&lt;/h2&gt;

&lt;p&gt;Com os testes passando, você dá uma olhada crítica no seu código e vê como pode melhorá-lo sem mudar o que ele faz. Você &lt;strong&gt;remove&lt;/strong&gt; redundâncias, limpa o código, e faz ajustes que deixam o código mais claro e fácil de manter.&lt;/p&gt;




&lt;h2&gt;
  
  
  Exemplo: Carrinho de Compras 🛒
&lt;/h2&gt;

&lt;p&gt;Imagine que você tem um objeto &lt;code&gt;Book&lt;/code&gt; com propriedades como &lt;em&gt;título&lt;/em&gt;, &lt;em&gt;ISBN&lt;/em&gt; e &lt;em&gt;preço&lt;/em&gt;, e um objeto &lt;code&gt;ShoppingCart&lt;/code&gt; onde você pode adicionar livros, calcular o preço total e remover livros.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Estado Vermelho 🚩:&lt;/strong&gt; Primeiro, você escreve um teste para a nova funcionalidade do seu carrinho de compras. Inicialmente, esse teste &lt;strong&gt;vai falhar&lt;/strong&gt; porque &lt;code&gt;ShoppingCart&lt;/code&gt; ainda não tem o método &lt;code&gt;add&lt;/code&gt; ou &lt;code&gt;getTotal&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ShoppingCart.test.js
const ShoppingCart = require('./ShoppingCart');
const Book = require('./Book');

describe('ShoppingCart', () =&amp;gt; {
  it('calculates total price for books in the cart', () =&amp;gt; {
    const book1 = new Book("book1", 10, "1");
    const book2 = new Book("book2", 20, "2");
    const cart = new ShoppingCart();
    cart.add(book1);
    cart.add(book2);
    expect(cart.getTotal()).toBe(30);
  });
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Estado Verde 🟢:&lt;/strong&gt; Depois, você implementa o mínimo necessário para fazer o teste passar. Aqui está uma implementação inicial para a classe &lt;code&gt;ShoppingCart&lt;/code&gt; e a classe &lt;code&gt;Book&lt;/code&gt;.&lt;br&gt;
Com isso, quando você &lt;strong&gt;rodar&lt;/strong&gt; o teste novamente, ele deve passar, porque &lt;code&gt;ShoppingCart&lt;/code&gt; agora realiza a funcionalidade básica esperada.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Book.js
class Book {
  constructor(title, price, isbn) {
    this.title = title;
    this.price = price;
    this.isbn = isbn;
  }
}

module.exports = Book;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ShoppingCart.js
class ShoppingCart {
  constructor() {
    this.items = [];
    this.total = 0;
  }

  add(book) {
    this.items.push(book);
    this.total += book.price;
  }

  getTotal() {
    return this.total;
  }
}

module.exports = ShoppingCart;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Estado Amarelo 🟡:&lt;/strong&gt; Pode ser interessante garantir que as propriedades do &lt;code&gt;Book&lt;/code&gt; sejam privadas e acessíveis apenas através de métodos &lt;code&gt;getters&lt;/code&gt; e &lt;code&gt;setters&lt;/code&gt;.&lt;br&gt;
Aqui está como poderia ser a &lt;strong&gt;refatoração&lt;/strong&gt; da classe &lt;code&gt;Book&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Book.js (refatorado)
class Book {
  constructor(title, price, isbn) {
    this._title = title;
    this._price = price;
    this._isbn = isbn;
  }

  get title() {
    return this._title;
  }

  get price() {
    return this._price;
  }

  get isbn() {
    return this._isbn;
  }
}

module.exports = Book;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Após a refatoração, você deve rodar os testes novamente para garantir que tudo ainda está funcionando como deveria. Isso completa um &lt;strong&gt;ciclo de TDD&lt;/strong&gt;. Agora, você pode adicionar mais funcionalidades ao carrinho, como remover itens, e para cada nova funcionalidade, você começaria um novo ciclo de TDD.&lt;/p&gt;




&lt;p&gt;A maior parte desse conteúdo veio do livro "Engenharia de Software Moderna", escrito por Marco Tulio Valente. Esse livro é um tesouro cheio de dicas sobre como criar testes do jeito certo, usando o que tem de mais novo e eficiente no mundo da programação. Entretanto, a única diferença, é que o livro é em Java e aqui eu adaptei para utilizar Javascript.&lt;/p&gt;




</description>
      <category>tdd</category>
      <category>javascript</category>
      <category>testing</category>
      <category>jest</category>
    </item>
    <item>
      <title>Mocks vs Stubs 🤼</title>
      <dc:creator>Ágatha</dc:creator>
      <pubDate>Sat, 06 Apr 2024 19:35:24 +0000</pubDate>
      <link>https://dev.to/htamagnus/mocks-vs-stubs-18e8</link>
      <guid>https://dev.to/htamagnus/mocks-vs-stubs-18e8</guid>
      <description>&lt;p&gt;Mocks são ferramentas úteis para &lt;strong&gt;simular comportamentos&lt;/strong&gt; de partes do seu código que &lt;strong&gt;dependem&lt;/strong&gt; de sistemas &lt;strong&gt;externos&lt;/strong&gt; ou complexos, permitindo testar seu código de forma &lt;strong&gt;isolada&lt;/strong&gt; e eficiente. Usar mocks ajuda a manter seus testes de unidade rápidos e focados apenas no que você quer testar, sem depender de serviços de rede, bancos de dados ou qualquer outro recurso externo.&lt;/p&gt;




&lt;h2&gt;
  
  
  Exemplo 📖
&lt;/h2&gt;

&lt;p&gt;Uma classe para pesquisa de livros, que interage com um serviço externo, neste cenário, temos uma função &lt;code&gt;getBook&lt;/code&gt; que busca dados de um livro por meio de uma API externa.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// BookSearch.js
class BookSearch {
  constructor(bookService) {
    this.bookService = bookService;
  }

  async getBook(isbn) {
    const json = await this.bookService.search(isbn);
    const data = JSON.parse(json);
    return { titulo: data.titulo };
  }
}

module.exports = BookSearch;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Problema 🚧
&lt;/h2&gt;

&lt;p&gt;Para testar &lt;code&gt;BookSearch&lt;/code&gt; isoladamente, precisamos de um &lt;code&gt;bookService&lt;/code&gt;, que é um &lt;strong&gt;serviço externo&lt;/strong&gt;. Testar diretamente com o serviço real tornaria o teste lento e instável, pois depende de uma rede e de um serviço que pode não estar sempre disponível ou responder de forma consistente.&lt;/p&gt;




&lt;h2&gt;
  
  
  Solução 🌟
&lt;/h2&gt;

&lt;p&gt;Para resolver esse problema, podemos criar um mock para &lt;code&gt;BookService&lt;/code&gt;. Em JavaScript, isso pode ser feito facilmente com o auxílio de bibliotecas de testes como Jest, que oferecem suporte embutido para criar mocks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// MockBookService.js
class MockBookService {
  async search(isbn) {
    if (isbn === 1234) {
      return JSON.stringify({ titulo: "Eng Soft Moderna" });
    }
    return JSON.stringify({ titulo: "NULL" });
  }
}

module.exports = MockBookService;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E o &lt;strong&gt;teste&lt;/strong&gt; poderia ser escrito assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// BookSearch.test.js
const BookSearch = require('./BookSearch');
const MockBookService = require('./MockBookService');

describe('BookSearch', () =&amp;gt; {
  test('getBook returns correct title', async () =&amp;gt; {
    const service = new MockBookService();
    const bookSearch = new BookSearch(service);
    const book = await bookSearch.getBook(1234);
    expect(book.titulo).toBe('Eng Soft Moderna');
  });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Neste cenário, o mock &lt;code&gt;MockBookService&lt;/code&gt; simula a resposta de uma API externa sem realmente fazer uma chamada de rede. Isso mantém o teste rápido e independente do ambiente externo. Embora não estejamos testando a interação real com o serviço externo, o mock nos permite verificar se &lt;code&gt;BookSearch&lt;/code&gt; está processando corretamente o JSON retornado e criando o objeto Book como esperado. Assim, podemos focar no teste da lógica interna de &lt;code&gt;BookSearch&lt;/code&gt;, garantindo que ela funciona corretamente, independentemente da confiabilidade ou disponibilidade do serviço externo.&lt;/p&gt;




&lt;h2&gt;
  
  
  Mocks vs Stubs 🤼
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Mocks&lt;/strong&gt;: São objetos que &lt;strong&gt;simulam&lt;/strong&gt; o comportamento de objetos reais de maneira controlada. Em testes de unidade, os mocks são usados para &lt;strong&gt;verificar&lt;/strong&gt; interações entre partes do código, ou seja, eles podem ser utilizados para garantir que certas funções foram chamadas, com quais parâmetros foram chamadas, e quantas vezes. Isso está relacionado ao teste do comportamento do código.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stubs&lt;/strong&gt;: São simplificações de objetos que substituem funcionalidades que não são o foco do teste. Eles oferecem respostas predefinidas a chamadas específicas. Diferente dos mocks, os stubs &lt;strong&gt;não&lt;/strong&gt; são usados para verificar interações ou comportamentos. Eles são mais sobre &lt;strong&gt;fornecer&lt;/strong&gt; um ambiente de teste controlado ao substituir partes do sistema que estão fora do escopo do teste atual.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Em JavaScript, usando Jest como exemplo, você pode criar tanto mocks quanto stubs de maneira simples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exemplo 📖
&lt;/h2&gt;

&lt;p&gt;Vamos considerar um exemplo simples onde temos uma função de negócio que depende de um serviço de envio de emails. Usaremos Jest para demonstrar tanto o conceito de mock (verificando o comportamento) quanto de stub (substituindo uma dependência complexa por uma versão simplificada).&lt;/p&gt;

&lt;h2&gt;
  
  
  Criando um Mock 🎭
&lt;/h2&gt;

&lt;p&gt;Supondo que temos uma classe &lt;code&gt;Mailer&lt;/code&gt; que queremos mockar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Mailer {
  send(email) {
    // Lógica de envio de email
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E um &lt;strong&gt;SUT&lt;/strong&gt; que usa Mailer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
function someBusinessLogic(mailer, message) {
  mailer.send(message);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos usar Jest para mockar &lt;code&gt;Mailer&lt;/code&gt; e verificar se send foi chamado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
const mailer = new Mailer();
jest.mock('./Mailer');

test('verifies Mailer.send is called', () =&amp;gt; {
  someBusinessLogic(mailer, "Hello");
  expect(mailer.send).toHaveBeenCalledWith("Hello");
});


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Criando um Stub 📌
&lt;/h2&gt;

&lt;p&gt;Se, ao contrário, só precisássemos de um &lt;code&gt;Mailer&lt;/code&gt;simplificado que não fizesse nada (apenas satisfazendo o tipo esperado sem influenciar o teste), poderíamos criar um stub assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const mailerStub = {
  send: jest.fn() // Isso cria um stub que satisfaz a interface mas não faz nada
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Embora a distinção entre &lt;strong&gt;mocks&lt;/strong&gt; e &lt;strong&gt;stubs&lt;/strong&gt; possa ser sutil, entender quando usar cada um pode ajudar a escrever testes mais claros e focados. Em JavaScript, com ferramentas como Jest, criar e usar mocks e stubs é bastante &lt;strong&gt;direto&lt;/strong&gt;, facilitando a implementação de testes de unidade eficazes que podem verificar comportamentos específicos (mocks) ou apenas substituir partes do sistema para isolamento (stubs).&lt;/p&gt;




&lt;h2&gt;
  
  
  Exemplo: Criando API em JavaScript 🌐
&lt;/h2&gt;

&lt;p&gt;Primeiro, temos um simples endpoint que calcula o IMC:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
// IMCController.js
const express = require('express');
const app = express();
app.use(express.json());

const IMCModel = {
  calculaIMC(peso, altura) {
    return peso / (altura * altura);
  }
};

app.get('/imc', (req, res) =&amp;gt; {
  const { peso, altura } = req.query;
  const imc = IMCModel.calculaIMC(parseFloat(peso), parseFloat(altura));
  res.send({ imc: `IMC: ${imc}` });
});

module.exports = app; // Para permitir importação no teste

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usando Jest, podemos &lt;strong&gt;testar&lt;/strong&gt; essa API sem precisar fazer chamadas reais. Jest nos permite mockar partes do Express para simular requisições e respostas.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// IMCController.test.js
const request = require('supertest');
const app = require('./IMCController');

describe('GET /imc', () =&amp;gt; {
  it('calculates IMC correctly', async () =&amp;gt; {
    const response = await request(app).get('/imc?peso=82&amp;amp;altura=1.80');
    expect(response.text).toEqual("{\"imc\":\"IMC: 25.30864197530864\"}");
  });
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No exemplo acima, &lt;strong&gt;não&lt;/strong&gt; precisamos de mocks para req e res porque o supertest cuida disso, permitindo que façamos chamadas ao nosso app Express como se fossem chamadas reais, mas tudo é simulado e nada vai para uma rede real.&lt;/p&gt;

&lt;p&gt;Em JavaScript, o uso de mocks e stubs é simplificado por bibliotecas como Jest, que permitem a você &lt;strong&gt;focar&lt;/strong&gt; na lógica dos testes sem se preocupar com a complexidade de criar e gerenciar esses objetos dublês. &lt;/p&gt;

&lt;p&gt;No entanto, &lt;strong&gt;cuidado:&lt;/strong&gt; o uso de mocks pode aumentar o acoplamento entre os testes e a implementação, tornando os testes frágeis a mudanças internas. Portanto, é importante usar mocks com cautela e sempre ponderar sobre a melhor abordagem para cada situação de teste.&lt;/p&gt;




&lt;p&gt;A maior parte desse conteúdo veio do livro "Engenharia de Software Moderna", escrito por Marco Tulio Valente. Esse livro é um tesouro cheio de dicas sobre como criar testes do jeito certo, usando o que tem de mais novo e eficiente no mundo da programação. Entretanto, a única diferença, é que o livro é em Java e aqui eu adaptei para utilizar Javascript.&lt;/p&gt;




</description>
    </item>
    <item>
      <title>Testabilidade em Javascript 🧪</title>
      <dc:creator>Ágatha</dc:creator>
      <pubDate>Sat, 06 Apr 2024 19:08:24 +0000</pubDate>
      <link>https://dev.to/htamagnus/testabilidade-em-javascript-397c</link>
      <guid>https://dev.to/htamagnus/testabilidade-em-javascript-397c</guid>
      <description>&lt;p&gt;Testabilidade é sobre o quão &lt;strong&gt;fácil&lt;/strong&gt; é escrever testes para um pedaço do seu código. Para que um código seja fácil de testar, ele precisa ser bem &lt;strong&gt;organizado&lt;/strong&gt; e seguir bons princípios de &lt;strong&gt;design&lt;/strong&gt;, como ter funções com responsabilidades claras e separadas, &lt;strong&gt;evitar&lt;/strong&gt; dependências complicadas entre partes do código e outras boas práticas de programação.&lt;/p&gt;




&lt;h2&gt;
  
  
  Exemplo: Cálculo de IMC 📏👤
&lt;/h2&gt;

&lt;p&gt;Num cenário inicial complicado para testes, poderia existir um cáculo de IMC, e  todo o cálculo e interação com o usuário, estar tudo &lt;strong&gt;misturado&lt;/strong&gt; numa &lt;strong&gt;única&lt;/strong&gt; função ou módulo. Isso faria com que testar o cálculo do IMC fosse &lt;strong&gt;difícil&lt;/strong&gt;, pois você teria que simular toda a interação do usuário.&lt;/p&gt;

&lt;p&gt;Para &lt;strong&gt;melhorar&lt;/strong&gt; a testabilidade, o melhor seria &lt;strong&gt;separar&lt;/strong&gt; a lógica do cálculo do IMC em um módulo separado, deixando a interação com o usuário para outra parte do código. Isso torna muito mais &lt;strong&gt;simples&lt;/strong&gt; escrever testes unitários para a lógica do IMC, pois você pode testá-la diretamente sem se preocupar com as partes de interação do usuário.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// IMCModel.js
class IMCModel {
  calculaIMC(peso, altura) {
    return peso / (altura * altura);
  }
}

module.exports = IMCModel;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E então, em outra parte do código, &lt;strong&gt;lidar&lt;/strong&gt; com a interação do usuário:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// IMCController.js
const IMCModel = require('./IMCModel');
const model = new IMCModel();

function calculaEExibeIMC(peso, altura) {
  const imc = model.calculaIMC(peso, altura);
  console.log(`Índice de Massa Corporal (IMC): ${imc}`);
}

calculaEExibeIMC(70, 1.75);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse exemplo, &lt;code&gt;IMCModel&lt;/code&gt; contém apenas a lógica para calcular o IMC, tornando-a fácil de testar de forma isolada. Não é necessário se preocupar com detalhes de como o peso e a altura são obtidos ou como o resultado é exibido. Essa separação de responsabilidades melhora a testabilidade do código.&lt;/p&gt;

&lt;p&gt;Essa abordagem mostra como o &lt;strong&gt;design&lt;/strong&gt; do código influencia diretamente na facilidade de testá-lo. &lt;strong&gt;Separar&lt;/strong&gt; a lógica de domínio da apresentação não só torna seu código mais limpo e organizado, mas também muito mais fácil de testar.&lt;/p&gt;




&lt;h2&gt;
  
  
  Exemplo: Chamada Assíncrona ⏳🔄
&lt;/h2&gt;

&lt;p&gt;Trabalhar com código assíncrono é algo bem comum, especialmente quando se trata de operações como chamadas de rede, leituras de arquivo, ou qualquer tarefa que leve tempo para ser concluída. Isso torna o teste dessas funções um pouco mais desafiador, mas não impossível.&lt;br&gt;
Vamos começar com uma classe &lt;code&gt;MyMath&lt;/code&gt; que contém uma função assíncrona para calcular PI e uma versão síncrona dessa mesma função para facilitar os testes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class MyMath {
  // Função síncrona que calcula PI.
  syncPI(prec) {
    let pi = 0;
    for (let k = 0; k &amp;lt; prec; k++) {
      pi += Math.pow(-1, k) / (2 * k + 1);
    }
    return pi * 4;
  }

  // Função assíncrona que utiliza a versão síncrona para calcular PI.
  async asyncPI(prec) {
    return new Promise((resolve) =&amp;gt; {
      setTimeout(() =&amp;gt; {
        const pi = this.syncPI(prec);
        resolve(pi);
      }, 1000); // Simula um cálculo que leva tempo com setTimeout.
    });
  }
}

module.exports = MyMath;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Testando o Código Assíncrono em JavaScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const MyMath = require('./MyMath');
const myMath = new MyMath();

describe('MyMath', () =&amp;gt; {
  test('asyncPI returns the correct PI value', async () =&amp;gt; {
    const prec = 10; // Define a precisão como exemplo.
    const piValue = await myMath.asyncPI(prec);
    expect(piValue).toBe(3.0418396189294032);
  });
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neste teste, você usa &lt;code&gt;async/await&lt;/code&gt; para esperar a promessa retornada por asyncPI ser resolvida. Jest espera automaticamente pela resolução da promessa quando você declara a função de teste com async.&lt;/p&gt;

&lt;p&gt;Isso mostra uma abordagem prática para &lt;strong&gt;melhorar&lt;/strong&gt; a testabilidade de código assíncrono: &lt;strong&gt;separar&lt;/strong&gt; a lógica complexa em funções síncronas que podem ser testadas independentemente e, em seguida, usar essas funções em operações assíncronas. Esse método não apenas torna seu código &lt;strong&gt;mais testável&lt;/strong&gt;, mas também o mantém organizado e fácil de entender.&lt;/p&gt;




&lt;p&gt;A maior parte desse conteúdo veio do livro "Engenharia de Software Moderna", escrito por Marco Tulio Valente. Esse livro é um tesouro cheio de dicas sobre como criar testes do jeito certo, usando o que tem de mais novo e eficiente no mundo da programação. Entretanto, a única diferença, é que o livro é em Java e aqui eu adaptei para utilizar Javascript.&lt;/p&gt;




</description>
      <category>javascript</category>
      <category>testing</category>
      <category>testabilidade</category>
      <category>software</category>
    </item>
    <item>
      <title>Princípios FIRST e Test Smells 🚀</title>
      <dc:creator>Ágatha</dc:creator>
      <pubDate>Sat, 06 Apr 2024 17:53:36 +0000</pubDate>
      <link>https://dev.to/htamagnus/principios-first-e-test-smells-33k7</link>
      <guid>https://dev.to/htamagnus/principios-first-e-test-smells-33k7</guid>
      <description>&lt;p&gt;Quando se fala em escrever testes de unidade de boa qualidade, há alguns princípios básicos, agrupados na sigla &lt;strong&gt;FIRST&lt;/strong&gt;, que podem ajudar bastante.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fast ⚡
&lt;/h2&gt;

&lt;p&gt;Os testes de unidade devem sempre ser rápidos. A ideia é que você consiga rodá-los o tempo todo, sem ficar esperando. Se você precisa de um café enquanto seus testes rodam, provavelmente eles não são rápidos o suficiente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Independent 🧍‍♂️
&lt;/h2&gt;

&lt;p&gt;Cada teste de unidade deve ser capaz de se virar sozinho. Não importa a ordem que você decide rodá-los; eles não devem depender uns dos outros.&lt;/p&gt;

&lt;h2&gt;
  
  
  Repeatable 🔁
&lt;/h2&gt;

&lt;p&gt;Se você rodar o mesmo teste várias vezes, o resultado deveria ser sempre o mesmo: ou o teste sempre passa, ou sempre falha. Testes que às vezes passam e às vezes falham sem motivo aparente são chamados de "flaky" ou erráticos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Self-checking ✅
&lt;/h2&gt;

&lt;p&gt;Uma vez finalizada a execução dos testes, o resultado deve ser auto-explicativo (passou/falhou). Desta forma, o resultado pode ser ligeiramente verificado e interpretado.&lt;/p&gt;

&lt;h2&gt;
  
  
  Timely 🕰️
&lt;/h2&gt;

&lt;p&gt;É uma boa ideia escrever os testes de unidade o quanto antes no seu processo de desenvolvimento. Muita gente até prefere escrever os testes antes do código que eles vão testar, isso ajuda a garantir que o seu código vai fazer exatamente o que você espera desde o começo.&lt;/p&gt;




&lt;h2&gt;
  
  
  Test Smells 🐟👃
&lt;/h2&gt;

&lt;p&gt;Alguns sinais no seu código de teste podem indicar que algo pode melhorar. Esses sinais são chamados de "Test Smells":&lt;/p&gt;

&lt;h2&gt;
  
  
  Teste Obscuro 🌫️🤔
&lt;/h2&gt;

&lt;p&gt;No código, um "Teste Obscuro" é assim: complicado, longo e difícil de entender. Testes devem ser &lt;strong&gt;simples e diretos&lt;/strong&gt;, para que qualquer pessoa possa entender o que está sendo testado e por quê. É importante ter uma lógica clara e de fácil entendimento.&lt;/p&gt;

&lt;h2&gt;
  
  
  Teste com Lógica Condicional ➰❓
&lt;/h2&gt;

&lt;p&gt;Um teste com muitos "se" e "senão" torna difícil de entender exatamente o que está sendo testado e em que condições. O ideal é que os testes de unidades sejam lineares, lógica condicional em testes prejudica o entendimento.&lt;/p&gt;

&lt;h2&gt;
  
  
  Duplicação de Código em Testes 📄🚫
&lt;/h2&gt;

&lt;p&gt;Se você tem código repetido em vários testes, talvez haja uma maneira mais eficiente de organizar isso.&lt;/p&gt;

&lt;p&gt;Test Smells são como um sinal de que talvez você possa simplificar ou organizar melhor seus testes. Não é que você nunca possa ter um "se" num teste ou um teste um pouco mais longo, mas é um lembrete para parar e pensar: &lt;em&gt;"Tem um jeito mais simples de fazer isso?”&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;A maior parte desse conteúdo veio do livro "Engenharia de Software Moderna", escrito por Marco Tulio Valente. Esse livro é um tesouro cheio de dicas sobre como criar testes do jeito certo, usando o que tem de mais novo e eficiente no mundo da programação. Entretanto, a única diferença, é que o livro é em Java e aqui eu adaptei para utilizar Javascript.&lt;/p&gt;




</description>
      <category>testing</category>
      <category>javascript</category>
      <category>softwaredevelopment</category>
      <category>software</category>
    </item>
    <item>
      <title>Quando Escrever Testes de Unidade?💡</title>
      <dc:creator>Ágatha</dc:creator>
      <pubDate>Sat, 06 Apr 2024 17:47:50 +0000</pubDate>
      <link>https://dev.to/htamagnus/quando-escrever-testes-de-unidade-85o</link>
      <guid>https://dev.to/htamagnus/quando-escrever-testes-de-unidade-85o</guid>
      <description>&lt;p&gt;Escrever testes de unidade é como se preparar para uma prova: você estuda um tópico e faz um teste para ver se realmente aprendeu. Existem &lt;strong&gt;duas formas principais&lt;/strong&gt; de fazer isso:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Depois de Programar&lt;/strong&gt;: Você cria uma parte do seu programa, como uma função que soma dois números. Depois de fazer isso funcionar, você escreve um teste que verifica se, quando você &lt;em&gt;soma&lt;/em&gt; 2 e 2, o resultado é &lt;em&gt;realmente&lt;/em&gt; 4. Você continua assim, criando mais partes do seu programa e escrevendo testes para cada uma.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Antes de Programar (TDD)&lt;/strong&gt;: Esse é o método &lt;a href="https://www.devmedia.com.br/test-driven-development-tdd-simples-e-pratico/18533"&gt;Test-Driven Development (Desenvolvimento Orientado por Testes)&lt;/a&gt;. Aqui você faz ao contrário: escreve o teste para a função de soma antes mesmo de fazer a função. Claro, o teste &lt;strong&gt;vai falhar&lt;/strong&gt;, porque a função ainda não existe. Depois, você cria a função de forma que faça o teste passar. Isso ajuda a manter o &lt;strong&gt;foco&lt;/strong&gt; em fazer apenas o necessário para que a função cumpra sua tarefa.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;Além de escrever testes antes ou depois de desenvolver, tem mais duas maneiras inteligentes de usar os testes de unidade:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Quando Aparecer um Bug&lt;/strong&gt;: Imagine que alguém te conta que encontrou um erro no seu programa. Uma ótima maneira de começar a resolver isso é escrevendo um teste que mostra esse erro acontecendo. Assim, você tem um teste que falha porque o programa não está fazendo o que deveria. Depois, você conserta o erro e, se o teste passar, você não só corrigiu o problema como também ganhou um novo teste para garantir que esse erro não volte a acontecer no futuro.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Durante a Depuração&lt;/strong&gt;: Se você está tentando entender por que uma parte do seu programa não está funcionando, resistir à tentação de só jogar um monte de &lt;strong&gt;&lt;code&gt;console.log&lt;/code&gt;&lt;/strong&gt; para ver o que está acontecendo. Em vez disso, é melhorar escrever um teste que verifica o comportamento que você está tentando consertar. Isso te ajuda a ser mais sistemático na depuração e ainda te deixa com um teste útil no final.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;E sobre quando &lt;strong&gt;não&lt;/strong&gt; escrever testes de unidade?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Não deixe para o final&lt;/strong&gt;: Esperar até que todo o programa esteja pronto para começar a testar geralmente não é uma boa ideia. Isso porque você pode acabar fazendo os testes com pressa e de forma &lt;strong&gt;superficial&lt;/strong&gt;, ou pior, pode acabar não fazendo os testes de jeito nenhum. Além disso, testar tudo de uma vez pode ser muito mais &lt;strong&gt;complicado&lt;/strong&gt; e &lt;strong&gt;menos eficiente&lt;/strong&gt; do que testar pedacinho por pedacinho à medida que você constrói o programa.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Não divida a responsabilidade&lt;/strong&gt;: É tentador pensar que alguém pode fazer o programa e outra pessoa pode testá-lo. Mas na verdade, é super &lt;strong&gt;importante&lt;/strong&gt; que quem escreveu um pedaço do código também escreva os testes para esse código. Isso ajuda a garantir que os testes estão cobrindo o que realmente importa e que o desenvolvedor entende profundamente como seu código deve funcionar.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Por fim, usar testes de unidade ao longo do desenvolvimento do seu programa não só &lt;strong&gt;ajuda&lt;/strong&gt; a encontrar e corrigir problemas mais rápido, mas também te dá a &lt;strong&gt;segurança&lt;/strong&gt; de que as mudanças que você faz não quebram coisas que já estavam funcionando.&lt;/p&gt;




&lt;h2&gt;
  
  
  Benefícios 🚀
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Encontrar Bugs Cedo&lt;/strong&gt;: A ideia é pegar os problemas enquanto você ainda está &lt;strong&gt;desenvolvendo&lt;/strong&gt;, antes de tudo ficar mais complicado (e caro) para consertar. Se você tem bons testes, é menos provável que erros chatos surpreendam você ou seus usuários lá na frente.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evitar Regressões&lt;/strong&gt;: Uma "regressão" é quando você muda alguma coisa no código para melhorar ou adicionar algo novo, mas acaba estragando outra coisa sem querer. Com testes de unidade, se você fizer uma mudança que cause uma regressão, provavelmente vai &lt;strong&gt;descobrir&lt;/strong&gt; rápido porque um dos seus testes vai falhar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentar e Especificar&lt;/strong&gt;: Além de te ajudar a não quebrar coisas, os testes também contam uma &lt;strong&gt;história&lt;/strong&gt; sobre como seu código deve se comportar. Se alguém quiser entender melhor uma parte do seu programa, pode começar olhando os testes para ver o que esperar dele. É quase como se os testes fossem um &lt;strong&gt;manual de instruções&lt;/strong&gt; que mostra como usar e o que esperar do seu código.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;Mas e no &lt;strong&gt;mundo real?&lt;/strong&gt; Empresas gigantes como Google e Facebook levam os testes de unidade &lt;strong&gt;super a sério&lt;/strong&gt;. No Google, por exemplo, eles não deixam nem o código entrar sem ter testes junto. Eles acham tão importante que têm até ferramentas que te &lt;strong&gt;lembram&lt;/strong&gt; de escrever os testes. No Facebook, os engenheiros também são responsáveis por testar seus próprios códigos e por garantir que novas mudanças não quebrem nada que já estava funcionando.&lt;/p&gt;

&lt;p&gt;Então, os testes de unidade não são só uma coisa teórica legal para "projetos escolares". Eles são usados &lt;strong&gt;o tempo todo&lt;/strong&gt;, em grandes projetos reais, para manter tudo funcionando suavemente e para evitar surpresas desagradáveis.&lt;/p&gt;




&lt;p&gt;A maior parte desse conteúdo veio do livro "Engenharia de Software Moderna", escrito por Marco Tulio Valente. Esse livro é um tesouro cheio de dicas sobre como criar testes do jeito certo, usando o que tem de mais novo e eficiente no mundo da programação. Entretanto, a única diferença, é que o livro é em Java e aqui eu adaptei para utilizar Javascript.&lt;/p&gt;




</description>
      <category>testing</category>
      <category>javascript</category>
      <category>jest</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Introdução a Testes de Unidade com Javascript 📘</title>
      <dc:creator>Ágatha</dc:creator>
      <pubDate>Sat, 06 Apr 2024 17:33:08 +0000</pubDate>
      <link>https://dev.to/htamagnus/introducao-a-testes-de-unidade-com-javascript-48n7</link>
      <guid>https://dev.to/htamagnus/introducao-a-testes-de-unidade-com-javascript-48n7</guid>
      <description>&lt;h2&gt;
  
  
  Testes Automatizados 🤖
&lt;/h2&gt;

&lt;p&gt;Fazer testes manualmente, ou seja, uma pessoa sentar e testar tudo passo a passo, leva &lt;strong&gt;muito tempo&lt;/strong&gt;, custa caro e é um trabalho que ninguém quer fazer. Além disso, sempre que algo no programa muda, tem que testar tudo de novo…&lt;br&gt;
Para entender melhor os testes automatizados, existe uma coisa chamada &lt;a href="https://medium.com/creditas-tech/a-pir%C3%A2mide-de-testes-a0faec465cc2" rel="noopener noreferrer"&gt;pirâmide de testes&lt;/a&gt;, que foi uma ideia do Mike Cohn. &lt;br&gt;
Imagine uma &lt;strong&gt;pirâmide&lt;/strong&gt; dividida em partes, onde cada parte mostra um tipo diferente de teste, organizados do mais &lt;strong&gt;simples&lt;/strong&gt; e rápido lá embaixo até os mais &lt;strong&gt;complexos&lt;/strong&gt; e demorados no topo. Essa pirâmide ajuda  a entender que não todos os testes são iguais: alguns são básicos e outros são bem detalhados, mas todos são importantes para garantir que o programa funcione direitinho.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fne0087ebdey1gzkv85x4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fne0087ebdey1gzkv85x4.png" alt="Image description" width="800" height="603"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;ol&gt;
&lt;li&gt;Na &lt;strong&gt;base da pirâmide&lt;/strong&gt;, temos os testes de unidade. Eles são como checar as peças de um quebra-cabeça uma por uma para ter certeza de que cada uma está certa. Cada teste desses olha para uma pequena parte do programa (geralmente uma única função ou classe) para ver se ela está fazendo o que deveria. Esses testes são muitos, rápidos de rodar e fáceis de fazer.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fky8lxyymmqzq83m2kuws.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fky8lxyymmqzq83m2kuws.png" alt="Image description" width="486" height="599"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;ol&gt;
&lt;li&gt;No &lt;strong&gt;meio da pirâmide&lt;/strong&gt;, encontramos os testes de integração ou testes de serviços. Imagine tentar ver se algumas peças do quebra-cabeça se encaixam como deveriam. Estes testes olham como diferentes partes do programa trabalham juntas. Por exemplo, eles podem testar se o programa salva as informações certinho no banco de dados. Esses testes são um pouco mais complexos que os testes de unidade e demoram mais para serem feitos e rodados.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6fa5bx3aqngkyt9mc74h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6fa5bx3aqngkyt9mc74h.png" alt="Image description" width="555" height="668"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;ol&gt;
&lt;li&gt;No &lt;strong&gt;topo da pirâmide&lt;/strong&gt;, temos os testes de sistema ou testes de interface com o usuário. Isso é como pegar o quebra-cabeça montado e ver se a imagem final está certa. Estes testes verificam o programa inteiro, de ponta a ponta, do jeito que um usuário de verdade usaria. São os testes mais complexos, mais demorados para rodar e custam mais caro. Eles também são "frágeis", o que quer dizer que pequenas mudanças no programa podem fazer com que esses testes precisem ser ajustados.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbn85ikirsjsl4bkbfywz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbn85ikirsjsl4bkbfywz.png" alt="Image description" width="729" height="716"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;Uma recomendação genérica é que esses três testes sejam implementados na seguinte proporção: 70% como testes de unidades; 20% como testes de serviços e 10% como testes de sistema.&lt;/p&gt;


&lt;h2&gt;
  
  
  Testes de Unidade 🧪
&lt;/h2&gt;

&lt;p&gt;Os testes de unidade são como &lt;strong&gt;mini-testes&lt;/strong&gt; para pedacinhos do seu programa. Imagine que seu programa é um robô, e cada teste de unidade verifica se uma &lt;em&gt;parte específica&lt;/em&gt; do robô (como um braço ou uma roda) está funcionando direitinho. Você escreve um pequeno teste para cada &lt;strong&gt;classe&lt;/strong&gt; do seu programa, que é basicamente um conjunto de instruções que o programa segue. Cada teste verifica se, ao pedir para essa &lt;strong&gt;classe&lt;/strong&gt; fazer alguma coisa (como somar dois números), ela realmente faz isso certo.&lt;/p&gt;

&lt;p&gt;Então, quando você olha para o seu programa, você tem duas grandes partes: &lt;strong&gt;as classes&lt;/strong&gt;, que são como o coração do programa, fazendo todo o trabalho; e os testes de unidade, que são como um checklist para garantir que cada parte do programa está fazendo seu trabalho corretamente. É como se tivesse um manual de "como as coisas deveriam funcionar" e estivesse marcando cada item para ter certeza de que está tudo ok.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiyi3qokzafj9wn30743q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiyi3qokzafj9wn30743q.png" alt="Image description" width="394" height="642"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A figura ilustra um sistema com &lt;strong&gt;várias classes&lt;/strong&gt;, que são como as diferentes partes de um programa, e os testes correspondentes a essas classes. Algumas classes têm &lt;strong&gt;mais de um teste&lt;/strong&gt; associado a elas, o que geralmente acontece porque essas partes do programa são mais complexas ou críticas, então precisam ser testadas em mais situações para ter certeza de que estão sempre funcionando bem.&lt;/p&gt;

&lt;p&gt;Por exemplo, a classe C1 é testada tanto por T1 quanto por T2, talvez ela tem um papel importante no programa e precisa ser muito bem verificada. Já a classe C2 não tem &lt;strong&gt;nenhum&lt;/strong&gt; teste associado, o que pode significar que os desenvolvedores ainda não fizeram testes para ela ou talvez ela não seja tão essencial assim para o funcionamento geral do sistema.&lt;/p&gt;

&lt;p&gt;Os testes de unidade são criados com a ajuda de ferramentas especiais chamadas &lt;strong&gt;frameworks xUnit&lt;/strong&gt;. Esses frameworks são como kits de ferramentas que ajudam a criar e rodar os testes automaticamente. O "x" no xUnit é substituído pelo nome da linguagem de programação usada. Atualmente já existem versões de frameworks xUnit para as principais linguagens de programação. &lt;/p&gt;

&lt;p&gt;Uma das vantagens de testes de unidade é que não é necessário aprender uma nova linguagem, por que os testes são implementados na &lt;strong&gt;mesma linguagem&lt;/strong&gt; do sistema que se pretende testar. Assim, os desenvolvedores podem se concentrar em &lt;strong&gt;melhorar&lt;/strong&gt; o programa, sem ter que gastar tempo extra aprendendo outras coisas só para testá-lo.&lt;/p&gt;

&lt;p&gt;Para explicar os conceitos de testes de unidade, vamos usar uma classe Stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Stack {
  constructor() {
    this.elements = [];
  }

  size() {
    return this.elements.length;
  }

  isEmpty() {
    return this.elements.length === 0;
  }

  push(elem) {
    this.elements.push(elem);
  }

  pop() {
    if (this.isEmpty())
      throw new Error('Stack is empty');
    return this.elements.pop();
  }
}

module.exports = Stack
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Stack = require('./stack');

describe('Stack', () =&amp;gt; {
  let stack;

  beforeEach(() =&amp;gt; {
    stack = new Stack();
  });

  test('pushes an element onto the stack', () =&amp;gt; {
    stack.push(1);
    expect(stack.size()).toBe(1);
  });

  test('pops an element from the stack', () =&amp;gt; {
    stack.push(2);
    expect(stack.pop()).toBe(2);
    expect(() =&amp;gt; stack.pop()).toThrow('Stack is empty');
  });

  test('checks if the stack is empty', () =&amp;gt; {
    expect(stack.isEmpty()).toBeTruthy();
  });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Usamos &lt;strong&gt;&lt;code&gt;describe&lt;/code&gt;&lt;/strong&gt; para agrupar testes relacionados a uma certa funcionalidade ou classe.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;beforeEach&lt;/code&gt;&lt;/strong&gt; é uma função que é executada antes de cada teste, configurando um ambiente limpo. Neste caso, estamos criando uma nova instância da pilha antes de cada teste.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;test&lt;/code&gt;&lt;/strong&gt; (ou &lt;strong&gt;&lt;code&gt;it&lt;/code&gt;&lt;/strong&gt; em algumas frameworks) é usado para definir um teste individual.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;expect&lt;/code&gt;&lt;/strong&gt; é uma função que verifica se o resultado corresponde ao esperado. Se não corresponder, o teste falha.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpd5wdtv35i1yrunj63h1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpd5wdtv35i1yrunj63h1.png" alt="Image description" width="547" height="228"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Para concluir, vamos mostrar o código completo do teste de unidade:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Stack = require('./stack'); 
describe('Stack', () =&amp;gt; {
  let stack;

  beforeEach(() =&amp;gt; {
    stack = new Stack();
  });

  test('new stack should be empty', () =&amp;gt; {
    // Verifica se a nova pilha está vazia.
    expect(stack.isEmpty()).toBeTruthy();
  });

  test('stack with one element should not be empty', () =&amp;gt; {
    // Verifica se a pilha não está vazia após adicionar um elemento.
    stack.push(10);
    expect(stack.isEmpty()).toBeFalsy();
  });

  test('stack should have correct size after pushing elements', () =&amp;gt; {
    // Verifica se o tamanho da pilha está correto após adicionar elementos.
    stack.push(10);
    stack.push(20);
    stack.push(30);
    expect(stack.size()).toBe(3);
  });

  test('stack should pop elements in the correct order', () =&amp;gt; {
    // Verifica se os elementos são retirados da pilha na ordem correta.
    stack.push(10);
    stack.push(20);
    stack.push(30);
    let result = stack.pop();
    expect(result).toBe(30); // O último elemento empilhado é o primeiro a ser retirado
    result = stack.pop();
    expect(result).toBe(20);
  });

  test('pop should throw an error on empty stack', () =&amp;gt; {
    // Verifica se uma exceção é lançada ao retirar um elemento de uma pilha vazia.
    stack.push(10);
    stack.pop(); // Deve funcionar bem
    expect(() =&amp;gt; stack.pop()).toThrow('Stack is empty'); // Espera-se um erro aqui
  });

});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Cada função &lt;strong&gt;&lt;code&gt;test&lt;/code&gt;&lt;/strong&gt; verifica uma afirmação específica sobre a classe &lt;strong&gt;&lt;code&gt;Stack&lt;/code&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;A função &lt;strong&gt;&lt;code&gt;expect&lt;/code&gt;&lt;/strong&gt; é seguida por uma "matcher function" (&lt;strong&gt;&lt;code&gt;toBeTruthy&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;toBeFalsy&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;toBe&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;toThrow&lt;/code&gt;&lt;/strong&gt;), que define o resultado esperado.&lt;/li&gt;
&lt;li&gt;A cláusula &lt;strong&gt;&lt;code&gt;toThrow&lt;/code&gt;&lt;/strong&gt; é usada para verificar se a função lança um erro quando tentamos fazer pop em uma pilha vazia.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fydx931a8f2g61gifn3or.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fydx931a8f2g61gifn3or.png" alt="Image description" width="562" height="270"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Definições 📚
&lt;/h2&gt;

&lt;p&gt;Mas o que de fato significa essas definições que aparecem quando rodam os testes, como "Test Suites"?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Teste&lt;/strong&gt;: É como um &lt;strong&gt;mini-desafio&lt;/strong&gt; que o programa precisa passar. No mundo dos testes, é um pedacinho de código que vai verificar se outra parte do programa faz o que deveria fazer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fixture&lt;/strong&gt;: É a &lt;strong&gt;preparação&lt;/strong&gt;, o que você faz antes de começar. Imagine que você precisa que algumas coisas estejam sempre no lugar certo antes de começar um teste. Por exemplo, se você vai testar se um carro anda, você precisa de um carro com motor, rodas e combustível. Isso é o fixture: o &lt;strong&gt;conjunto&lt;/strong&gt; de coisas que você prepara para poder realizar seus testes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Casos de Teste (Test Case)&lt;/strong&gt;: Isso é como uma coleção de mini-desafios relacionados. É uma classe que tem vários métodos de teste dentro dela. Você pode pensar nela como uma lista de verificações que seu programa precisa passar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Suíte de Testes (Test Suite)&lt;/strong&gt;: Quando você tem várias coleções de mini-desafios (casos de teste) e quer passar por todas elas de uma vez, isso se chama suíte de testes. É um pacote que junta muitos testes diferentes para rodar todos juntos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sistema sob Teste (System Under Test, SUT)&lt;/strong&gt;: É o próprio programa que você está testando. Assim como numa peça de teatro, o "sistema sob teste" é o ator principal, aquele que está sob os holofotes e sendo avaliado para ver se faz tudo certinho. Em outras palavras, é o código real que as pessoas vão usar.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Pensando num exemplo prático: se você tivesse um aplicativo de &lt;strong&gt;lista de tarefas&lt;/strong&gt;, os &lt;strong&gt;"testes"&lt;/strong&gt; seriam os códigos que verificam se você pode adicionar e remover tarefas corretamente, a &lt;strong&gt;"fixture"&lt;/strong&gt; seria a lista inicial que você configura para os testes, os "&lt;strong&gt;casos de teste"&lt;/strong&gt; seriam todas as verificações relacionadas à lista de tarefas, o &lt;strong&gt;"suíte de testes"&lt;/strong&gt; seria um conjunto completo de testes não só da lista de tarefas, mas talvez também de outras partes do aplicativo, e o &lt;strong&gt;"SUT"&lt;/strong&gt; seria o aplicativo de lista de tarefas inteiro que você está testando.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Todas as imagens de explicação de pirâmide de testes foram tiradas do livro eng de software moderna. Disponível em: &lt;a href="https://engsoftmoderna.info/cap8.html" rel="noopener noreferrer"&gt;https://engsoftmoderna.info/cap8.html&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;A maior parte desse conteúdo veio do livro "Engenharia de Software Moderna", escrito por Marco Tulio Valente. Esse livro é um tesouro cheio de dicas sobre como criar testes do jeito certo, usando o que tem de mais novo e eficiente no mundo da programação. Entretanto, a única diferença, é que o livro é em Java e aqui eu adaptei para utilizar Javascript.&lt;/p&gt;




</description>
      <category>testes</category>
      <category>javascript</category>
      <category>software</category>
      <category>testing</category>
    </item>
    <item>
      <title>Estruturas de projetos baseado em MVC com NodeJS e MongoDB 🏗️</title>
      <dc:creator>Ágatha</dc:creator>
      <pubDate>Tue, 17 Oct 2023 19:21:24 +0000</pubDate>
      <link>https://dev.to/htamagnus/estruturas-de-projetos-baseado-em-mvc-com-nodejs-e-mongodb-3poo</link>
      <guid>https://dev.to/htamagnus/estruturas-de-projetos-baseado-em-mvc-com-nodejs-e-mongodb-3poo</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdhu9tbf0wkztehk4xdvq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdhu9tbf0wkztehk4xdvq.png" alt="Image description" width="213" height="312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A estrutura de projeto que eu vou descrever não é um padrão de design específico, mas é uma &lt;strong&gt;organização&lt;/strong&gt; comum que se baseia em &lt;strong&gt;princípios&lt;/strong&gt; do padrão de design MVC &lt;em&gt;(Model-View-Controller)&lt;/em&gt; em um contexto de desenvolvimento utilizando &lt;strong&gt;NodeJS&lt;/strong&gt; e &lt;strong&gt;MongoDB&lt;/strong&gt;.&lt;br&gt;
Ou seja, é uma estrutura de projeto que segue os princípios do MVC, mas não é necessariamente chamada de MVC em si.&lt;/p&gt;

&lt;p&gt;Essa é uma abordagem para deixar o código mais organizado e limpo, separando as responsabilidades em &lt;strong&gt;pastas diferentes&lt;/strong&gt;. Em resumo, é uma estrutura de projeto que é &lt;strong&gt;influenciada&lt;/strong&gt; pelo padrão MVC, mas não é um framework ou implementação formal.&lt;/p&gt;




&lt;h2&gt;
  
  
  controllers 🎮
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsrgjw3d71mgraotno39f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsrgjw3d71mgraotno39f.png" alt="Image description" width="214" height="96"&gt;&lt;/a&gt;&lt;br&gt;
A pasta &lt;strong&gt;controllers&lt;/strong&gt; é responsável por guardar os controladores do aplicativo. Os controladores são responsáveis por manipular &lt;strong&gt;requisições HTTP&lt;/strong&gt;, chamar &lt;strong&gt;funções&lt;/strong&gt; dos modelos e retornar as &lt;strong&gt;respostas&lt;/strong&gt; para o cliente. Normalmente cada arquivo nessa pasta vai representar uma entidade ou recurso do aplicativo e contém funções pra lidar com operações relacionadas a ele.&lt;/p&gt;




&lt;h2&gt;
  
  
  data 📂
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb2y0ah1ljzc5jby4vj72.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb2y0ah1ljzc5jby4vj72.png" alt="Image description" width="214" height="73"&gt;&lt;/a&gt;&lt;br&gt;
A pasta &lt;strong&gt;data&lt;/strong&gt; é responsável por armazenar dados brutos: arquivos JSON, CSV ou scripts que foram gerados no banco de dados. Pode  também conter scripts Node.js que são responsáveis por inicializar o banco de dados com dados iniciais. A pasta data é &lt;strong&gt;flexível&lt;/strong&gt; e seu conteúdo pode variar de projeto para projeto, dependendo das necessidades específicas.&lt;/p&gt;




&lt;h2&gt;
  
  
  models 🏗️
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffwlbefj883dxifwf11i9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffwlbefj883dxifwf11i9.png" alt="Image description" width="220" height="92"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A pasta models contém os modelos do MongoDB, que definem a &lt;strong&gt;estrutura dos documentos&lt;/strong&gt; no banco de dados. Cada arquivo nessa pasta representa um tipo de documento e define os campos, validações e métodos.&lt;/p&gt;




&lt;h2&gt;
  
  
  public 🌐
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp0pxayy1mmkya1z4abay.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp0pxayy1mmkya1z4abay.png" alt="Image description" width="219" height="75"&gt;&lt;/a&gt;&lt;br&gt;
A pasta public é usada para armazenar &lt;strong&gt;arquivos estáticos&lt;/strong&gt;, como arquivos CSS, Javascript, imagens e arquivos de mídia. É interessante criar &lt;strong&gt;subdiretórios&lt;/strong&gt; para categorizar os diferentes tipos de recursos, como o CSS para estilização e JS para scripts.&lt;/p&gt;




&lt;h2&gt;
  
  
  routes 🚦
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv12m1looidkkdtzqiqyh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv12m1looidkkdtzqiqyh.png" alt="Image description" width="216" height="71"&gt;&lt;/a&gt;&lt;br&gt;
É onde as definições de rota e controladores associados são mantidas. Gerenciam as &lt;strong&gt;solicitações HTTP&lt;/strong&gt;. Cada rota pode responder a diferentes métodos HTTP, como GET, POST, PUT, DELETE, etc. Geralmente, cada arquivo nessa pasta corresponde a um grupo de rotas relacionadas a um recurso específico.&lt;/p&gt;




&lt;h2&gt;
  
  
  util 🛠️
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbpex1i9ezfm3ayvs8pqj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbpex1i9ezfm3ayvs8pqj.png" alt="Image description" width="214" height="53"&gt;&lt;/a&gt;&lt;br&gt;
Essa pasta pode conter &lt;strong&gt;utilitários&lt;/strong&gt; ou módulos de uso geral que não se encaixam bem em outras categorias. Geralmente possui funções de utilidade, validações e configurações comuns.&lt;/p&gt;




&lt;h2&gt;
  
  
  views 👁️
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqamwm0bspi3gg60ur21u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqamwm0bspi3gg60ur21u.png" alt="Image description" width="211" height="112"&gt;&lt;/a&gt;&lt;br&gt;
A pasta views é onde os arquivos de modelo são armazenados e usados para renderizar a &lt;strong&gt;interface do usuário&lt;/strong&gt;. Esses arquivos geralmente contém código HTML. Geralmente se utiliza um &lt;strong&gt;mecanismo de template&lt;/strong&gt; como EJS, Handlebars, Pug e etc.&lt;/p&gt;




&lt;p&gt;Organizando o projeto dessa maneira deixa cada pasta com um papel específico, o que torna a manutenção e colaboração mais eficiente, pois as &lt;strong&gt;responsabilidades&lt;/strong&gt; estão bem definidas. A estrutura exata de um projeto vai variar de acordo com as necessidades do aplicativo e a preferência do time. Entretanto, a organização em camadas e a separação de responsabilidades são princípios importantes a serem seguidos.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>mongodb</category>
      <category>mvc</category>
    </item>
    <item>
      <title>Mongoose: entendendo o básico 📖</title>
      <dc:creator>Ágatha</dc:creator>
      <pubDate>Thu, 12 Oct 2023 19:52:57 +0000</pubDate>
      <link>https://dev.to/htamagnus/mongoose-entendendo-o-basico-2i57</link>
      <guid>https://dev.to/htamagnus/mongoose-entendendo-o-basico-2i57</guid>
      <description>&lt;p&gt;Mongoose é um biblioteca de Modelagem de Dados de Objeto (ou ODM, do inglês: Object Data Modeling) para &lt;strong&gt;MongoDB&lt;/strong&gt; e &lt;strong&gt;Node.js&lt;/strong&gt;. Ele gerencia o relacionamento entre dados, fornece a validação de esquemas e é usado como tradutor entre objetos no código e a representação desses objetos no MongoDB.&lt;/p&gt;




&lt;h2&gt;
  
  
  conexão com o banco (MongoDB) 🔌
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const mongoose = require("mongoose"); // O primeiro passo é importar o módulo mongoose, ele fornece uma camada de abstração para simplificar a interação com o MongoDB.

mongoose
  .connect(
    "mongodb+srv://hta:agatha@cluster0.r2eb6bu.mongodb.net/shop?retryWrites=true&amp;amp;w=majority"
  ) 
// Esta linha estabelece uma conexão com o banco de dados MongoDB
  .then((result) =&amp;gt; {
    app.listen(3006);
  }) 
//  Este bloco é executado quando a conexão com o banco de dados é estabelecida com sucesso. A função app.listen(3006) inicia o servidor da aplicação na porta 3007. 
  .catch((err) =&amp;gt; {
    console.log(err);
  }); 
//  Se ocorrer algum erro durante a conexão com o banco de dados, este bloco é executado. O erro é capturado e registrado no console 

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  definir um schema 📄
&lt;/h2&gt;

&lt;p&gt;O esquema define as propriedades do documento através de um &lt;strong&gt;objeto&lt;/strong&gt;, onde o nome da chave corresponde ao nome da propriedade na coleção. Esses são os tipos de esquemas permitidos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Array&lt;/li&gt;
&lt;li&gt;Boolean (ou booleano, em português)&lt;/li&gt;
&lt;li&gt;Buffer&lt;/li&gt;
&lt;li&gt;Date (ou formato de data, em português)&lt;/li&gt;
&lt;li&gt;Mixed (um tipo genérico/flexível de dados)&lt;/li&gt;
&lt;li&gt;Number (ou numérico, em português)&lt;/li&gt;
&lt;li&gt;ObjectId&lt;/li&gt;
&lt;li&gt;String
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const mongoose = require('mongoose'); 
// Importa o módulo Mongoose, que é necessário para criar modelos e interagir com bancos de dados MongoDB

const Schema = mongoose.Schema; 
// Armazenamos a classe schema do mongoose na variável 'Schema'

const productSchema = new Schema({ 
//Criamos um novo esquema para representar a estrutura dos documentos que serão armazenados em uma coleção do MOngoDB. O objeto passado para o construtor do Schema define os campos e suas propriedades.
    title: {
        type: String,
        required: true
    },
    price: {
        type: Number,
        required: true
    },
    description: {
        type: String,
        required: true
    }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Portanto, o &lt;strong&gt;productSchema&lt;/strong&gt; descreve a estrutura dos documentos que representam produtos. Cada documento precisa ter um título, preço e descrição, e esses campos devem conter os tipos de dados especificados. &lt;br&gt;
Agora, o productSchema pode ser usado para &lt;strong&gt;criar modelos&lt;/strong&gt; de dados que se encaixam nesse esquema. Esses modelos são usados para interagir com a coleção no banco de dados MongoDB e realizar operações como criar, ler, atualizar e excluir documentos.&lt;/p&gt;




&lt;h2&gt;
  
  
  exportar um modelo 📦
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;module.exports = mongoose.model('Product', productSchema);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Para exportar um modelo no mongoose, você define um nome para ele e indica o nome da entidade. &lt;br&gt;
Essa linha de código combina o esquema productSchema com o nome 'Product' para criar um modelo que representa documentos com a estrutura definida no esquema. &lt;br&gt;
Esse modelo pode ser usado para e*&lt;em&gt;xecutar operações no banco de dados&lt;/em&gt;*, como criar, ler, atualizar e excluir documentos na coleção 'Product'. &lt;br&gt;
Após essa exportação, o modelo 'Product' estará disponível para uso em outros arquivos e partes do seu aplicativo Node.js.&lt;/p&gt;




&lt;h2&gt;
  
  
  buscando um produto 🔍
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exports.getProducts = (req, res, next) =&amp;gt; {
  Product.find()
    .then((products) =&amp;gt; {
      res.render("shop/product-list", {
        prods: products,
        pageTitle: "All Products",
        path: "/products",
      });
    })
    .catch((err) =&amp;gt; {
      console.log(err);
    });
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O método &lt;strong&gt;find()&lt;/strong&gt; do Mongoose é uma das operações mais comuns e fundamentais para recuperar documentos de um banco de dados MongoDB. Ele é usado para &lt;strong&gt;consultar documentos em uma coleção&lt;/strong&gt; com base em critérios de pesquisa e retorna um ou mais documentos que correspondem a esses critérios. Essa chamada procura todos os documentos no banco de dados MongoDB associados ao modelo Product.&lt;/p&gt;




&lt;h2&gt;
  
  
  atualizando um produto 🔄
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exports.postEditProduct = (req, res, next) =&amp;gt; {
  const prodId = req.body.productId; //  Obtém o ID do produto a ser editado do corpo da solicitação
  const updatedTitle = req.body.title;
  const updatedPrice = req.body.price;
  const updatedImageUrl = req.body.imageUrl;
  const updatedDesc = req.body.description;

  Product.findById(prodId) // Esta linha faz uma consulta ao banco de dados para localizar o produto com o ID especificado (prodId) usando o método findById() do modelo Product. Isso é feito para recuperar o produto existente que será atualizado.
    .then((product) =&amp;gt; { // Se o produto for encontrado com sucesso, a função dentro deste bloco .then() será executada. Ela recebe o produto encontrado como argumento (representado pela variável product).
      product.title = updatedTitle;
      product.price = updatedPrice;
      product.description = updatedDesc;
      product.imageUrl = updatedImageUrl;
      return product.save(); // Após a atualização das propriedades do produto, a função .save() é chamada para salvar essas alterações no banco de dados.
    })
    .then((result) =&amp;gt; {
      console.log("UPDATED PRODUCT!");
      res.redirect("/admin/products");
    })
    .catch((err) =&amp;gt; console.log(err)); // Se houver algum erro durante o processo de atualização ou salvamento do produto, o erro será capturado neste bloco .catch() e registrado no console.
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse controlador é responsável por a*&lt;em&gt;tualizar as informações de um produto&lt;/em&gt;* no banco de dados com base nos dados enviados por um formulário de edição. Ele primeiro localiza o produto pelo ID, atualiza suas propriedades e, em seguida, salva as alterações no banco de dados. Se bem-sucedido, a resposta é redirecionada para a página de administração de produtos; caso contrário, qualquer erro é registrado no console.&lt;/p&gt;




&lt;h2&gt;
  
  
  deletando um produto 🗑️
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exports.postDeleteProduct = (req, res, next) =&amp;gt; {
  const prodId = req.body.productId; //Obtém o ID do produto que deve ser excluído a partir do corpo da solicitação POST.
  Product.findByIdAndRemove(prodId) // Esta linha realiza a exclusão do produto com o ID fornecido (prodId) no banco de dados MongoDB. Ela utiliza o método findByIdAndRemove do modelo Mongoose Product para localizar e remover o documento correspondente no banco de dados com base no ID.
    .then(() =&amp;gt; {
      console.log("DESTROYED PRODUCT");
      res.redirect("/admin/products");
    }) // Se a exclusão do produto for bem-sucedida, o código dentro deste bloco .then() é executado. Neste caso, ele imprime "DESTROYED PRODUCT" no console e, em seguida, redireciona o usuário para a página "/admin/products".
    .catch((err) =&amp;gt; console.log(err)); //Se ocorrer algum erro durante o processo de exclusão do produto, o erro é capturado neste bloco .catch() e é registrado no console.
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esta função controladora é usada para &lt;strong&gt;excluir um produto do banco de dados&lt;/strong&gt; com base no ID do produto fornecido na solicitação POST. Se a exclusão for bem-sucedida, uma mensagem é registrada no console e o usuário é redirecionado para a página de administração de produtos. Se houver algum erro durante o processo de exclusão, o erro é registrado no console.&lt;/p&gt;




&lt;h2&gt;
  
  
  relacionando schemas 🧩
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Schema = mongoose.Schema;

const productSchema = new Schema({
    userId: {
        type: Schema.Types.ObjectId,
        ref: "User", // estabelece uma referencia ao uma diferente coleção chamada User
        required: true
    }
});

module.exports = mongoose.model('Product', productSchema);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;O productSchema inclui um campo chamado userId, que é um tipo Schema.Types.ObjectId e faz referência à coleção 'User'. Isso significa que o valor desse campo será o ID de um documento na coleção 'User'.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Schema = mongoose.Schema;

const userSchema = new Schema({
  cart: {
    items: [
      {
        productId: {
          type: Schema.Types.ObjectId,
          ref: "Product",
          required: true,
        },
        quantity: { type: Number, required: true },
      },
    ],
  },
});
module.exports = mongoose.model("User", userSchema);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Cada item do carrinho é representado por um objeto que inclui o productId (que é uma referência à coleção 'Product') e a quantity (a quantidade do produto no carrinho).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Isso permite que um usuário tenha produtos em seu carrinho e que esses produtos sejam referências a documentos da coleção 'Product'. A relação entre os usuários e os produtos é estabelecida por meio do campo productId.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>mongoose</category>
      <category>mongodb</category>
      <category>node</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
