Skip to content

Instantly share code, notes, and snippets.

@pedropbazzo
Created January 31, 2021 03:08
Show Gist options
  • Save pedropbazzo/e75ec742549f34d22fe4f0058af23d2e to your computer and use it in GitHub Desktop.
Save pedropbazzo/e75ec742549f34d22fe4f0058af23d2e to your computer and use it in GitHub Desktop.
npm i request --save-dev mocha
Instalamos o Mocha como uma dependência dev, pois o módulo não exige a presença dela em uma configuração de produção. Caso queira aprender mais sobre os pacotes do Node.js ou o npm, confira nosso guia sobre Como usar os módulos do Node.js com o npm e o package.json.
Por fim, vamos criar o arquivo que terá o código do nosso módulo:
touch index.js
Com isso, estamos prontos para criar nosso módulo. Abra o index.js em um editor de texto como o nano:
nano index.js
Vamos começar definindo a classeTodos. Essa classe contém todas as funções que precisamos para gerenciar nossa lista de AFAZERES. Adicione as linhas de código a seguir ao index.js:
todos/index.js
class Todos {
constructor() {
this.todos = [];
}
}
module.exports = Todos;
Começamos o arquivo criando uma classe Todos. Sua função constructor() não recebe argumentos, de forma que não precisamos fornecer valores para instanciar objetos para esta classe. Tudo o que fazemos ao inicializar um objeto de Todos é criar uma propriedade de todos que é uma matriz vazia.
A linha modules (módulos) permite que outros módulos do Node.js exijam nossa classe Todos. Sem exportar explicitamente a classe, o arquivo de teste que criaremos mais tarde não seria capaz de usá-la.
Vamos adicionar uma função para retornar a matriz de todos que armazenamos. Escreva nas seguintes linhas em destaque:
todos/index.js
class Todos {
constructor() {
this.todos = [];
}
list() {
return [...this.todos];
}
}
module.exports = Todos;
Nossa função list() retorna uma cópia da matriz que é usada pela classe. Ele faz uma cópia da matriz usando a sintaxe de desestruturação do JavaScript. Fazemos uma cópia da matriz, para que alterações que o usuário faz na matriz retornada por list() não afete a matriz usada pelo objeto Todos.
Nota: as matrizes do JavaScript são tipos de referência. Isso significa que, para qualquer atribuição de variável a uma matriz ou invocação de função com uma matriz como parâmetro, o JavaScript se refere à matriz original criada. Por exemplo, caso tenhamos uma matriz com três itens chamados x e criemos uma nova variável, y, tal que y = x, y e x se referem à mesma coisa. Qualquer alteração que fizermos em y na matriz tem impacto na variável x e vice-versa.
Agora, vamos escrever a função add(), que adiciona um novo item de AFAZERES:
todos/index.js
class Todos {
constructor() {
this.todos = [];
}
list() {
return [...this.todos];
}
add(title) {
let todo = {
title: title,
completed: false,
}
this.todos.push(todo);
}
}
module.exports = Todos;
Nossa função add() recebe uma string e a coloca em uma nova propriedade de um objeto do JavaScript. O novo objeto também tem uma propriedade completed (finalizado), que é definida como false (falso) por padrão. Depois, adicionamos este novo objeto à nossa matriz de AFAZERES.
Uma funcionalidade importante em um gestor de AFAZERES é marcar itens como finalizados. Para essa implantação, vamos fazer um loop que percorre nossa matriz todos para encontrar o item de AFAZERES que o usuário está procurando. Caso um seja encontrado, marcaremos o processo como concluído. Caso nenhum seja encontrado, emitiremos um erro.
Adicione a função complete(), desta forma:
todos/index.js
class Todos {
constructor() {
this.todos = [];
}
list() {
return [...this.todos];
}
add(title) {
let todo = {
title: title,
completed: false,
}
this.todos.push(todo);
}
complete(title) {
let todoFound = false;
this.todos.forEach((todo) => {
if (todo.title === title) {
todo.completed = true;
todoFound = true;
return;
}
});
if (!todoFound) {
throw new Error(`No TODO was found with the title: "${title}"`);
}
}
}
module.exports = Todos;
Salve o arquivo e saia do editor de texto.
Temos agora um gerenciador de AFAZERES básico, que podemos testar. Em seguida, vamos testar manualmente nosso código para ver se o aplicativo está funcionando.
Passo 2 — Testando o código manualmente
Neste passo, executaremos as funções do nosso código e observaremos o resultado para garantir que ele corresponda às nossas expectativas. Isso é chamado de teste manual. É provável que seja aplicada a metodologia de testes mais comum. Apesar do fato de que iremos automatizar nosso teste mais tarde com o Mocha, vamos primeiro testar manualmente nosso código para ter uma melhor ideia de como o teste varia entre diferentes frameworks de teste.
Vamos adicionar dois itens de AFAZERES ao nosso aplicativo e marcar um deles como completo. Inicie o REPL do Node.js na mesma pasta que o arquivo index.js:
node
Você verá o prompt > no REPL que nos diz que podemos inserir o código do JavaScript. Digite o seguinte no prompt:
const Todos = require('./index');
Com o require(), carregamos o módulo de AFAZERES em uma variável Todos. Lembre-se de que nosso módulo retorna a classe Todos por padrão.
Agora, vamos instanciar um objeto para essa classe. No REPL, adicione esta linha de código:
const todos = new Todos();
Podemos utilizar o objeto todos para verificar nossos trabalhos de implementação. Vamos adicionar nosso primeiro item de AFAZERES:
todos.add("run code");
Até agora, não vimos nenhum resultado em nosso terminal. Vamos verificar se armazenamos nosso item de AFAZERES "run code" (executar o código), obtendo uma lista de todos os nossos AFAZERES:
todos.list();
Você verá este resultado em seu REPL:
Output
[ { title: 'run code', completed: false } ]
Este é o resultado esperado: temos um item de AFAZERES em nossa matriz de AFAZERES. Além disso, o arquivo não está concluído por padrão.
Vamos adicionar outro item de AFAZERES:
todos.add("test everything");
Marque o primeiro item de AFAZERES como concluído:
todos.complete("run code");
Nosso objeto todos agora está gerenciando dois itens: "run code" e "test everything" (testar tudo). O item de AFAZERES "run code" também será concluído. Vamos confirmar isso, chamando list() novamente:
todos.list();
O REPL irá gerar como resultado:
Output
[
{ title: 'run code', completed: true },
{ title: 'test everything', completed: false }
]
Agora, saia do REPL com o seguinte:
.exit
Confirmamos que nosso módulo se comporta da maneira como esperávamos. Embora não tenhamos colocado nosso código em um arquivo de teste ou usado uma biblioteca de teste, testamos nosso código manualmente. Infelizmente, essa forma de teste gasta muito tempo se feita todas as vezes que fizermos uma mudança. Em seguida, vamos utilizar testes automatizados no Node.js e ver se podemos resolver esse problema com o framework de testes Mocha.
Passo 3 — Escrevendo seu primeiro teste com o Mocha e Assert
No último passo, testamos manualmente nosso aplicativo. Isso funciona para casos individuais de uso. Entretanto, conforme nosso módulo aumenta em escala, menos viável se torna esse método. À medida que testamos novas características, precisamos ter certeza de que adicionamos funcionalidades que não criaram problemas com funcionalidades já existentes. Seria interessante testarmos todas as funcionalidades para cada alteração no código mais uma vez. Porém, fazer isso manualmente necessitaria de muito esforço e estaria propenso a erros.
Uma prática mais eficiente poderia ser configurar testes automatizados. Esses testes seguem scripts escritos como qualquer outro bloco de código. Executamos nossas funções com entradas definidas e inspecionamos seus efeitos para garantir que se comportam como esperamos. À medida que nossa base de código cresce, também crescem nossos testes automatizados. Ao escrevermos novos testes juntamente com as funcionalidades, podemos verificar se todos os módulos ainda funcionam — tudo isso sem precisar lembrar como usar cada função toda vez.
Neste tutorial, estamos usando o framework de testes Mocha com o módulo assert do Node.js. Vamos colocar um pouco a mão na massa para ver como eles funcionam juntos.
Para começar, crie um novo arquivo para armazenar nosso código de teste:
touch index.test.js
Agora, utilize seu editor de texto preferido para abrir o arquivo de teste. Você pode usar o nano, assim como anteriormente:
nano index.test.js
Na primeira linha do arquivo de texto, carregaremos o módulo de AFAZERES, assim como fizemos no shell do Node.js. Depois disso, carregaremos o módulo assert para quando escrevermos nossos testes. Adicione as linhas a seguir:
todos/index.test.js
const Todos = require('./index');
const assert = require('assert').strict;
A propriedade strict do módulo assert nos permitirá usar testes de igualdade especiais recomendados pelo Node.js. Esses testes são também adequados para testes futuros, já que representam mais casos de uso.
Antes de escrevermos os testes, vamos discutir como o Mocha organiza o nosso código. Geralmente, os testes estruturados no Mocha seguem este modelo:
describe([String with Test Group Name], function() {
it([String with Test Name], function() {
[Test Code]
});
});
Note duas funções chave: describe() e it(). A função describe() é usada para agrupar testes semelhantes. Ela não é exigida para que o Mocha realize testes, mas o agrupamento de testes torna nosso código de teste mais fácil de ser mantido. Recomenda-se que você agrupe seus testes de uma maneira que torne fácil a atualização dos que são semelhantes de uma só vez.
O it() contém nosso código de teste. É aqui que interagimos com as funções do nosso módulo e usamos a biblioteca assert. Muitas funções it() podem ser definidas em uma função describe().
Nosso objetivo nesta seção é usar o Mocha e o assert para automatizar nosso teste manual. Faremos isso passo a passo, começando com nosso bloco describe. Adicione isto ao seu arquivo após as linhas do módulo:
todos/index.test.js
...
describe("integration test", function() {
});
Com este bloco de código, criamos um agrupamento para nossos testes integrados. Os testes de unidade testariam uma função de cada vez. Os integration tests (testes de integração) verificam o quão bem as funções dentro de um módulo de diferentes módulos funcionam juntas. Quando o Mocha executa nosso teste, todos os testes dentro desse bloco describe serão executados no grupo "integration test".
Vamos adicionar uma função it(), para que possamos começar a testar o código do nosso módulo:
todos/index.test.js
...
describe("integration test", function() {
it("should be able to add and complete TODOs", function() {
});
});
Note como escolhemos um nome descritivo para o teste. Caso alguém execute nosso teste, ficará imediatamente claro o que está passando ou falhando. Normalmente, um aplicativo bem testado é um aplicativo bem documentado. Além disso, os testes podem ser, por vezes, um tipo de documentação eficaz.
Para nosso primeiro teste, criaremos um novo objeto Todos e verificaremos se ele não tem itens nele:
todos/index.test.js
...
describe("integration test", function() {
it("should be able to add and complete TODOs", function() {
let todos = new Todos();
assert.notStrictEqual(todos.list().length, 1);
});
});
A primeira linha de código instanciou um novo objeto Todos, assim como faríamos no REPL do Node.js ou outro módulo. Na segunda linha nova, usamos o módulo assert.
A partir do módulo assert, usamos o método notStrictEqual(). Essa função recebe dois parâmetros: o valor que queremos testar (chamado de valor actual (real)) e o valor que esperamos obter (chamada de valor expected (esperado)). Caso ambos os argumentos sejam iguais, notStrictEqual() emite um erro para fazer o teste falhar.
Salve e saia do index.test.js.
O caso base será verdadeiro, pois o comprimento deveria ser 0, que é diferente de 1. Vamos confirmar isso executando o Mocha. Para fazer isso, precisamos modificar nosso arquivo package.json. Abra o seu arquivo package.json com seu editor de texto:
nano package.json
Agora, modifique sua propriedade scripts para que se pareça com isto:
todos/package.json
...
"scripts": {
"test": "mocha index.test.js"
},
...
Acabamos de alterar o comportamento do comando CLI test do npm. Ao executarmos npm test, o npm irá revisar o comando que acabamos de digitar no package.json. Ela irá procurar pela biblioteca do Mocha em nossa pasta node_modules e executará o comando mocha com nosso arquivo de teste.
Salve e saia do package.json.
Vamos ver o que acontece ao executarmos nosso teste. Em seu terminal, digite:
npm test
O comando gerará o seguinte resultado:
Output
> todos@1.0.0 test your_file_path/todos
> mocha index.test.js
integrated test
✓ should be able to add and complete TODOs
1 passing (16ms)
Em primeiro lugar, este resultado nos mostra qual grupo de testes está prestes a ser executado. Para cada teste dentro de um grupo, pula-se uma linha no caso de teste. Vemos nosso nome de teste da forma como o descrevemos na função it(). A marcação no lado esquerdo do caso de teste indica que o teste foi aprovado.
No final, recebemos um resumo de todos os nossos testes. Em nosso caso, nosso único teste foi aprovado e foi concluído em 16ms (o tempo varia de computador para computador).
Nossa testagem foi iniciada com sucesso. No entanto, este caso de teste atual pode permitir falsos positivos. Um falso positivo é um caso de teste que é aprovado quando na verdade deveria falhar.
Neste momento, verificamos que o comprimento da matriz não é igual a 1. Vamos modificar o teste para que essa condição seja verdadeira quando não deveria. Adicione as linhas a seguir ao index.test.js:
todos/index.test.js
...
describe("integration test", function() {
it("should be able to add and complete TODOs", function() {
let todos = new Todos();
todos.add("get up from bed");
todos.add("make up bed");
assert.notStrictEqual(todos.list().length, 1);
});
});
Salve e saia do arquivo.
Adicionamos dois itens de AFAZERES. Vamos executar o teste para ver o que acontece:
npm test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment