Tutorial: Testando Aplicações RESTFul API em Node.Js com Mocha & Chai
Olá a todos! *Novamente*. 😀 Sim…. como prometido, aqui estamos falando sobre algo que é de grande importância em qualquer desenvolvimento de aplicação de software: TDD e BDD. E no mundo Node.Js/JavaScript não seria diferente!
Vamos dar continuidade ao último artigo que escrevi [AQUI] onde nós desenvolvemos uma aplicação RESTFul API em Node.Js & Express.Js com MongoDb. Dessa vez, iremos desenvolver uma aplicação RESTFul usando os conceitos de TDD e BDD com os frameworks de teste: Mocha e Chai!
Se desejam seguir esse tutorial, que continuem com a leitura e …
Breves palavras….
Nesse tutorial, estaremos desenvolvendo uma aplicação RESTful API com Node.Js. Porém, testando a aplicação desenvolvida com Mocha e Chai. Novamente…. para que os conceitos fiquem bem explícitos, iremos desenvolver uma aplicação CRUD para uma Livraria. 😉
Bom… se vocês seguiram o tutorial do meu último artigo não terão dificuldades nenhuma em seguir esse daqui. Pelo contrário, se sentirão cada vez mais motivados em desenvolver aplicações em Node.Js e melhor: testados. Mas, para quem já tem conceitos em Node.Js, mas não em testes com Mocha e Chai, aqui segue alguns requisitos para seguir com esse tutorial deve saber:
- JavaScript (conceitos básicos);
- Node.Js (caso não saiba, leiam o meu outro tutorial — AQUI)
- Express.Js (idem acima);
- Sintaxe ES6;
- MongoDb (idem acima);
Vamos usar o nosso amigo: PostMan para que possamos testar as nossas APIs criadas. O Postman pode ser baixado AQUI.
A IDE a qual estarei utilizando para desenvolver esse tutorial é: Visual Code. Pode ser baixado por AQUI. Não há empecilhos em usar outras IDEs. Eu prefiro o VS Code, porque tenho curtido bastante, posso debugar os códigos em JavaScript de maneira fácil e há snippets para várias linguagens. Para quem ainda não conhece, fica a dica! É uma excelente IDE para desenvolver! E está superando as expectativas de vários Desenvolvedores.! 😀
Afinal…. O que é o Mocha :S
Assim como em outras linguagens, o JavaScript dispõe de frameworks de teste. E no mundo Node.Js também não seria diferente. E é aí que entra o Mocha (lê-se moca).
O Mocha é um framework do JavaScript para Node.Js que permite realizar testes Assíncronos. Digamos que ele provê um ambiente em que nós podemos usar a nossa biblioteca de asserções prediletas para testar o nosso código em Node.Js. E como o próprio site do Mocha diz sobre esse framework….
Sim. O Mocha é muito utilizado pelos desenvolvedores de Node.Js por ser: Simples, flexível e porque não divertido! 😀 😀 ❤
Um outro fator relevante que vem fazendo o Mocha ganhar muitos adeptos em suas aplicações é que ele provê inúmeros grandes recursos. E o site mostra uma longa lista. Aqui vão algumas que faz muitos amarem o Mocha:
- Suporte simples para aplicações assíncronas, incluindo promises;
- Suporte assíncrono para testes de timeout;
- Before, after, before each, after each hooks (um ambiente muito útil e que permite codificarmos teste de maneira limpa seguindo o conceito de Code Clean e mehor: para cada teste que desenvolvemos;
- Uso de qualquer biblioteca de asserção que você deseja. Nesse tutorial estaremos usando o Chai.
Ótimo! Não é mesmo? Até o Captain Awesome concorda!! 😀
O melhor amigo do Mocha: Chai! ❤
Sim. Geralmente quando você desenvolve um teste com Mocha, os desenvolvedores usa uma biblioteca chamada Chai.
Mas, para que serviria o Chai?! O Chai nos permite fazer os testes das chamadas HTTP. Por exemplo, suponhamos que a nossa aplicação há um método GET que retorna um arquivo JSON. Como podemos testar se esse método está realmente retornando os dados para esse arquivo? É aí que entra a biblioteca de asserção do Chai. O Mocha por si só não consegue realizar esse tipo de verificação e teste.
A biblioteca Chai nos dá total liberdade de escolher a interface que desejamos: ‘should’, ‘expect’, ‘assert’, a qual todos estão disponíveis para codificarmos os nossos testes em nossa aplicação. Outro ponto a mencionar aqui, a biblioteca do Chai usar facilmente asserções de requisições em HTTP que melhor nos convêm!
Chega de falarmos e vamos pôr a mão na massa! Literalmente! 😉
Preparando o Ambiente e Projeto :D
Show Time! Hora de preparar para podermos desenvolver a nossa aplicação. Para isso, peço que abrem o seu IDE desejado e crie os seguintes arquivos e pastas no projeto:
Estarei desenvolvendo e comitando o código dessa aplicação no meu repositório do GitHub. Sintam-se à vontade em fazer um fork ou até mesmo baixarem AQUI.
Vamos entender o que foi posto aqui no nosso projeto. Notem que a pasta /config contêm 3 arquivos JSONs. Assim como os nomes sugerem, eles conterão configurações particulares para propósitos específicos, a qual veremos no decorrer desse projeto.
Nesse artigo, estaremos alternando entre 2 banco de dados. Um que será para desenvolvimento e um outro para fins de teste. Assim, esses arquivos contem a URI do MongoDb no formato JSON:
- dev.json;
- default.json;
- test.json;
Incluem esse bloco de código em ambos nos arquivos: dev.json e default.json:
E no arquivo test.json…
Resolvi colocar a imagem em vez de um bloco de código para que fique a fácil compreensão. A partir daqui, estaremos usando o bloco de códigos do wordpress. 😉
Nesses dois arquivos é onde vocês definirão a URI da sua base de dados. No meu caso, estou usando o MongoDb em cloud: Modulus. Caso não saiba usar o Modulus, veja o meu outro artigo AQUI.
p.s.: o arquivo default.json é opcional. Porém, é uma boa prática de desenvolvimento e sem contar que esse arquivo será recarregado todas as vezes que formos iniciar a aplicação. Caso queiram saber mais informações sobre o formato de diretório de arquivos de configuração cliquem AQUI.
E finalmente notem o diretório /test/livro.js. É justamente aí que toda a brincadeira irá funcionar! 😀
Vamos prosseguir!!!
Configuração do Package.Json
Coloquem o seguinte bloco de código no arquivo package.json:
{
"name": "livraria-app",
"version": "1.0.0",
"description": "Tutorial: Testando Aplicações RESTFul API em Node.Js com Mocha & Chai",
"main": "server.js",
"author": "Glaucia Lemos",
"license": "ISC",
"dependencies": {
"body-parser": "^1.15.1",
"config": "^1.20.1",
"express": "^4.13.4",
"mongoose": "^4.4.15",
"morgan": "^1.7.0",
"use-strict": "^1.0.1"
},
"devDependencies": {
"chai": "^3.5.0",
"chai-http": "^2.0.1",
"mocha": "^2.4.5"
},
"scripts": {
"start": "node server.js",
"test": "mocha --timeout 10000"
},
"repository": {
"type": "git",
"url": "https://github.com/glaucia86/tutorial-crud-nodejs-mocha-chai"
}
}
Assim como no último tutorial que escrevi, esse arquivo package.json não deve surpreender ninguém aqui. Aqui estamos definindo as dependências necessárias para a nossa aplicação. Com uma leve mudança aqui: definimos o script de execução dos testes da nossa aplicação.
Para que possamos executar o Mocha adicinei aqui um –timeout 10000 para que nos permita buscar os dados na base de dados que estaremos hospendando no MongoLab ou Modulus. Então, eu acho que 2 segundos é um tempo suficiente para a realização dessa busca! 😉
Agora, vamos baixar essas dependências? Vocês se lembram como fazer isso? Se não… explico aqui de novo 😉
Vão até o diretório do projeto onde está sendo desenvolvido e digite o seguinte comando:
npm install
Ao fazermos isso, o npm fará o seu trabalho em baixar os pacotes necessários (como segue a imagem abaixo) em nosso projeto. E se notar, na pasta do projeto surgirá a famosa pasta ‘node_modules’. Precisaremos dele! 😀
Beleza! Agora é a hora de nós codificarmos o serviço que irá executar a nossa aplicação e claro testá-lo. 😀
Vamos levantar o Serviço! 😀
Arquivo: server.js
O arquivo server.js é o arquivo principal onde estaremos levantando a nossa aplicação. Peço que codifiquem o bloco de código abaixo:
/**
* Arquivo: server.js
* Author: Glaucia Lemos
* Description: Arquivo principal e responsável por executar a nossa aplicação.
* Data: 16/10/2016
*/
var express = require('express');
var app = express();
var mongoose = require('mongoose');
var morgan = require('morgan');
var bodyParser = require('body-parser');
var port = 3000;
var livro = require('./app/routes/livro');
var config = require('config'); // aqui estaremos carregando a localização da base de dados através dos arquivos JSON.
//Opção das base de dados:
var options = {
server:{ socketOptions: {keepAlive: 1, connectTimeoutMS: 30000 }},
replset:{ socketOptions: {keepAlive: 1, connectTimeoutMS: 30000 }}
};
//Conexão com a base de dados:
mongoose.connect(config.DBHost, options);
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'Erro ao conectar com a Base de Dados....: '));
//Essa parte do código estaremos mostrando os logs quando acontecer os testes:
if(config.util.getEnv('NODE_ENV') !== 'test') {
//Aqui estamos usando 'morgan'. Ele é responsável por realizar as requisições de logger no middleware para Node.Js
app.use(morgan('combined'));
}
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.text());
app.use(bodyParser.json({ type: 'application/json' }));
app.get("/", (req, res) => res.json({message: "Sejam Bem-Vindos a Nossa Livraria READ IT!"}));
//Definição das rotas para: GET & POST:
app.route("/livro")
.get(livro.selecionarTodosLivros)
.post(livro.adicionarLivro);
//Definição das rotas para: GET, DELETE & PUT
app.route("/livro/:id")
.get(livro.selecionarLivroPorId)
.delete(livro.excluirLivro)
.put(livro.atualizarLivro);
app.listen(port);
console.log("Aplicação executando na porta " + port);
module.exports = app;
Wow… quanta coisa não? E a estrutura está bem diferente da outra aplicação que desenvolvemos anteriormente. Tudo isso por conta do ES6. Mas, antes… vamos dar um brief do que está acontecendo aqui! 😉
- 1) Notem que fizemos um require do módulo ‘config‘. Ele será responsável por acessar o arquivo de configuração que definimos no projeto ‘NODE_ENV‘. Com isso, ele conseguirá obter o parâmetro da conexão da base de dados através da URI do MongoDb. Isso nos ajudará a manter o “verdadeiro” banco de dados limpo dos testes da outra base de dados que está oculto na nossa aplicação para futuros usuários.
- 2) O NODE_ENV é uma variável de ambiente que realizará o contra teste para poder desativar o log feito pelo ‘morgan’. Ou seja, ele irá interferir na saída dos testes realizados.
- 3) A última linha de código exportará o serviço para fins de testes.
Bom… diferente do outro tutorial… não tente agora executar a aplicação. Porque dará erro! Mas, por quê? Simples! Notem que já definimos as rotas dos métodos: GET, PUT, DELETE e POST. Ao tentarmos executar a nossa aplicação agora, a aplicação nos indicará que está faltando as funções que farão a lógica do CRUD. Algo que ainda não codificamos ainda 😉
Veja na imagem abaixo o erro….
Hora de criar o Modelo e as Rotas!
Agora vem a hora de criarmos o modelo para Livro. No projeto vá até o arquivo: livro.js na pasta app/model e adicione o seguinte bloco de código abaixo:
/**
* Arquivo: models/livro.js
* Author: Glaucia Lemos
* Description: Arquivo responsável pelo modelo do 'Livro' para realizar a conexão com a base
* de dados via Moongose.
* Data: 18/10/2016
*/
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
//Aqui vem a definição da esquema do 'Livro':
var LivroSchema = new Schema(
{
titulo: { type: String, required: true },
autor: { type: String, required: true },
ano: { type: Number, required: true },
paginas: { type: Number, required: true, min: 1 },
criadoEm: { type: Date, default: Date.now },
},
{
versionKey: false
}
);
//Aqui irá setar o parâmetro 'criadoEm' para a data atual:
LivroSchema.pre('save', next => {
var dataAtual = new Date();
if(!this.criadoEm) {
this.criadoEm = dataAtual;
}
next();
});
//Aqui realizará a exportação do 'LivroSchema' para usar em qualquer lugar:
module.exports = mongoose.model('livro', LivroSchema);
O esquema do nosso ‘Livro‘ contém: titulo, autor, número de páginas, o ano da publicação e a data de criação na base de dados. Setei a propriedade ‘versionKey‘ para false, já que não haverá utilidade para esse tutorial.
p.s.: notem que a sintaxe do callback da função .pre() é uma arrow function. Ou seja, de acordo com a definição no Mozilla Developer :
Uma expressão arrow function possui uma sintaxe mais curta quando comparada com expressões de função (function expressions) e vincula o valor de this de maneira léxica. Arrow functions sempre são anônimas.
Bom, agora já entendemos tudo que precisamos saber sobre o modelo. Então, vamos mover as rotas.
No arquivo livro.js, porém contido no diretório /app/routes, coloque o seguinte bloco de código:
/*
* Arquivo: routes/livro.js
* Author: Glaucia Lemos
* Description: Arquivo responsável pelas rotas das APIS
* Data: 18/10/2016
*/
var mongoose = require('mongoose');
var Livro = require('../models/livro');
/* 1) Método: Selecionar Livros (acessar em: GET http://localhost:3000/livro */
function selecionarTodosLivros(req, res) {
//Aqui estamos definindo a query do banco para que possa retornar todos os livros:
var query = Livro.find({});
query.exec(function(error, livros) {
if(error)
res.send(error);
//Caso não haja erros, então retornará para o usuário:
res.json(livros);
});
}
/* 2) Método: Criar Livro (acessar em: POST http://localhost:3000/livro) */
function adicionarLivro(req, res) {
//Criamos um novo livro:
var novoLivro = new Livro(req.body);
//Aqui estaremos salvando todos os campos na base de dados:
novoLivro.save(function(error, livro) {
if(error) {
res.send(error);
} else {
res.json({ message: "Livro adicionado com Sucesso!", livro });
}
});
}
/** 3) Método: Selecionar Por Id (acessar em: GET http://localhost:3000/livro/:id ) */
function selecionarLivroPorId(req, res) {
Livro.findById(req.params.id, function(error, livro) {
if(error)
res.send(error);
//Caso não haja erros, retornar para o usuário:
res.json(livro);
});
}
/** 4) Método: Excluir (acessar em: http://localhost:3000/livro/:id ) */
function excluirLivro(req, res) {
Livro.remove({ _id: req.params.id }, function(error, resultado) {
res.json({ message: "Livro excluído com Sucesso!", resultado });
});
}
/* 5) Método: Atualizar (acessar em: PUT http://localhost:3000/livro/:id ) */
function atualizarLivro(req, res) {
//Para que eu possa atualizar um livro, preciso primeiramente encontrar o id do livro que desejo atualizar:
Livro.findById({ _id: req.params.id }, function(error, livro) {
if(error)
res.send(error);
//Caso não haja erros, retornar a atualização para o usuário:
Object.assign(livro, req.body).save(function(error, livro) {
if(error)
res.send(error);
res.json({ message: "Livro Atualizado com Sucesso", livro });
});
});
}
//Aqui iremos exportar todas as funções criadas acima:
module.exports = { selecionarTodosLivros, adicionarLivro, selecionarLivroPorId, excluirLivro, atualizarLivro };
Vamos entender agora algumas coisitas desenvolvidas aqui 😉
- As rotas declaradas aqui são nada mais do que as operações do CRUD (GET, PUT, DELETE & POST) que irão persistir na nossa base de dados.
- Na função updateLivro() usamos Objetct.assign é uma nova convenção/função do ES6 que nos permite substituir as propriedades comuns do ‘Livro’ com req.body permitindo que os deixe intactos.
- No final do código estamos exportando o objeto usando uma sintaxe mais rápida do que pares de chaves e valor, com o objetivo de evitar repetições inúteis.
Ótimo! Já terminamos essa parte! E agora nós temos uma aplicação pronta! 😀
Testando App no PostMan!
Agora vamos executar a aplicação! Para isso vamos precisar do Postaman para sabermos se tudo o que desenvolvemos até aqui está funfando! 😀
Execute o comando abaixo:
npm start
Você verá a seguinte mensagem no seu terminal:
Show! Agora abre o Postman e vamos testar a nossa API! 😀
Método: adicionarLivro: POST /livro
Vamos adicionar alguns livros na nossa base de dados. Para isso, segue como a imagem abaixo:
Adicionei 3 livros na nossa API. Você pode adicionar quantos desejar! 😉
Como podem notar na imagem acima, a requisição POST está funcionando perfeitamente! Agora… vamos para a próxima requisição: GET.
Método: selecionarLivroPorId: GET /livro
Agora já com os livros adicionados execute a requisição GET no Postman e veja o resultado!
Show! Retornou justamente os 3 livros que cadastrei! Sintoma de que está tudo funcionando corretamente!
Vamos seguir adiante!
Método: AtualizarLivro: PUT /livro/:id
Vamos atualizar algum livro e vejamos o resultado:
Feito! Escolhi pelo ID, como podem ver acima e atualizei o número de páginas do livro, que antes era 1080 e agora são 1050!
Método: selecionarLivroPorId: GET /livro/:id
Vamos agora listar um determinado livro da nossa base! 😉 E o resultado foi….
Perfeito! Agora vamos para o último teste: DELETE!
Método: ExcluirLivro: DELETE /livro/:id
Agora vamos deletar um livro da nossa base, colocando o id do que será deletado. E…
Como vocês podem perceber, todas as operações da nossa API está funcionando perfeitamente! Mas, será que realizar esses ou alguns testes pelo PostMan garante a integridade do que desenvolvemos? Será que ele fará uma análise se realmente o comportamento da nossa API está funcionando de maneira correta?
Claro que não!
Numa aplicação do mundo real, se faz necessário criar testes de unidade para sabermos se aquilo que realmente desenvolvemos está realmente tudo certo. Pois devemos garantir ao cliente que, o produto final que estamos entregando a ele está tudo funcionando de maneira integrada! E é aí que entrará o TDD no lado do server-side: Mocha & Chai.
Realizando o VERDADEIRO Teste! 😀
Primeiramente peço que entre na pasta /teste/livro.js e codifiquem o código abaixo:
/*
* Arquivo: routes/livro.js
* Author: Glaucia Lemos
* Description: Arquivo responsável por realizar o TDD com Mocha & Chai no lado do server da nossa app.
* Data: 21/10/2016
*
*/
process.env.NODE_ENV = 'test';
var mongoose = require('mongoose');
var Livro = require('../app/models/livro');
//Aqui estamos declarando as dependências necessárias para realizar os nossos testes!
var chai = require('chai');
var chaiHttp = require('chai-http');
var server = require('../server');
var should = chai.should();
chai.use(chaiHttp);
//Aqui é o bloco principal que executará o nossos testes:
describe('Livros', function() {
beforeEach(function(done) {
//Sempre depois de executar o nosso teste, iremos limpar a nossa base de dados:
Livro.remove({}, function(error) {
done();
});
});
/**
* Teste da rota: /GET
*/
describe('/GET livro', function() {
it('Deve retornar todos os livros', function(done) {
chai.request(server)
.get('/livro')
.end(function(error, res) {
//Se tudo der certo deve retornar o status: 200 - OK
res.should.have.status(200);
//E em seguida retornar em um array todos os livros cadastrados na base de dados:
res.body.should.be.a('array');
res.body.length.should.be.eql(0);
done();
});
});
});
Quanta coisa não?! Calma, vou explicar cada coisa aqui agora que está acontecendo:
- Primeiro observe a variável NODE_ENV que recebe test. Isso nos permitirá mudar o arquivo de configuração assim que for carregado para o servidor que irá se conectar ao banco de dados de teste evitando assim registros de log no cmd.
- Nós fizemos ‘require’ dos módulos de dev-dependencies declarados no arquivo package.json para que possamos usar Chai e o Mocha.
- Definimos o ‘should’ que será executado pelo ‘chai.should()’ para os testes nas requisições do HTTP e então nós chamamos o ‘chai’ para usar o chai HTTP.
Logo em seguida, ele começa a ‘descrever’ (describe) os blocos de código para melhorar a assertions criadas e que consequentemente irá refletir na saída da linha de comando, como veremos mais tarde! 😉
‘beforeEach’ é um bloco responsável por executar antes de cada descrição (describe) dos blocos de código no mesmo nível. Mas, por que fizemos desse jeito? Simples. Ele irá remover qualquer livro a partir do banco de dados para começar a aplicação vazia sempre que um teste é executado.
Testando a rota /GET
Agora chegou o momento de testarmos o que acabamos de codificar! Chai irá executar uma solicitação GET para o servidor. E as assertions (afirmações) sobre as variáveis que irá satisfazer ou rejeitar o primeiro parâmetro do bloco de código que deverá retornar todos os livros através do GET. Precisamente, dado que a aplicação está vazia o resultado da solicitação deve ser:
- Status 200.
- O resultado deve ser um array.
- Desde que a livraria está vazia, presumimos que o tamanho deverá ser igual a 0.
Observem que a sintaxe ‘should’ é muito intuitiva assim como uma linguagem natural humana.
Bom, agora execute o seguinte comando:
npm test
E abaixo veja o resultado do nosso primeiro teste:
Notem que o nosso teste passou e a saída refletiu justamente o que definimos no nosso bloco de código dentro do ‘describe’.
Testando a rota /POST
Agora vamos verificar a nossa API supondo que estamos tentando adicionar um livro sem a informação das páginas ao servidor. O resultado deverá ser que não responderá com a mensagem de erro.
Codifique o código abaixo no arquivo de teste:
...
/**
* Teste da rota: /POST
*/
describe('/POST livro', function() {
it('Não deve retornar o POST do livro criado, uma vez que não foi definido o campo: paginas', function(done) {
//Aqui simulamos a criação de um livro, porém sem definir a página do livro:
var livro = {
titulo: "Javascript. O Guia Definitivo",
autor: "David Flanagan",
ano: 2012
}
chai.request(server)
.post('/livro')
.send(livro)
.end(function(error, res) {
res.should.have.status(200);
res.body.should.be.a('object');
res.body.should.have.property('errors');
res.body.errors.should.have.property('paginas');
res.body.errors.paginas.should.have.property('kind').eql('required');
done();
});
});
...
Bom… aqui nós adicionamos um teste falho para a solicitação POST. Mas, vamos analisar as assertions (afirmações):
- Deverá retornar status 200.
- A resposta do body deve retornar um object.
- Uma das propriedades do body (que nesse caso será o campo: paginas) deverá retornar errors.
- Errors deve sinalizar que está faltando o campo paginas.
- E finalmente ‘paginas’ deve retornar uma propriedade ‘tipo’ igual a ‘required’ com o objetivo de retornar a razão pela qual está dando mensagem de erro no servidor.
Observem que quando enviamos um livro com a solicitação POST usamos a função send().
Agora vamos executar o nosso teste e verificar a saída do que definimos acima:
Sensacional! O nosso teste está executando corretamente!
Mas, antes de escrever um novo teste, vamos esclarecer 2 coisas:
- Primeiramente, por que a resposta do servidor foi estruturada daquela maneira. Se você ler a função callback para a rota do /POST, vocês irão notar que em caso de faltar algum campo obrigatório (required) o servidor irá enviar de volta uma mensagem de erro para o mongoose. Faça esse teste com o POSTMAN e verifique a resposta 😉
- Em caso de faltar algum campo, devemos retornar o status 200. E isso é para deixar de maneira mais simples para que possamos aprender a testar as nossas rotas. No entanto, por boa prática, sugiro que retorne um status 206 (Partial Content).
Agora vamos enviar um livro com todos os campos de uma vez. Segue o bloco de código completo:
...
/**
* Teste da rota: /POST
*/
describe('/POST livro', function() {
it('Não deve retornar o POST do livro criado, uma vez que não foi definido o campo: paginas', function(done) {
//Aqui simulamos a criação de um livro, porém sem definir a página do livro:
var livro = {
titulo: "Javascript. O Guia Definitivo",
autor: "David Flanagan",
ano: 2012
}
chai.request(server)
.post('/livro')
.send(livro)
.end(function(error, res) {
res.should.have.status(200);
res.body.should.be.a('object');
res.body.should.have.property('errors');
res.body.errors.should.have.property('paginas');
res.body.errors.paginas.should.have.property('kind').eql('required');
done();
});
});
it('Deve Criar um livro', function(done) {
var livro = {
titulo: "Javascript. O Guia Definitivo",
autor: "David Flanagan",
paginas:1080,
ano: 2012
}
chai.request(server)
.post('/livro')
.send(livro)
.end(function(error, res) {
res.should.have.status(200);
res.body.should.be.a('object');
res.body.should.have.property('message').eql('Livro adicionado com Sucesso!');
res.body.livro.should.have.property('titulo');
res.body.livro.should.have.property('autor');
res.body.livro.should.have.property('paginas');
res.body.livro.should.have.property('ano');
done();
});
});
});
...
Desta vez o valor esperado que deverá retornar é um object com uma mensagem dizendo que nós adicionamos com sucesso um livro. Agora você já deve estar ficando mais familiarizado com as assertions que nós desenvolvemos aqui. O resultado é como de acima:
Lindo!
Testando a rota /GET/:ID
Agora vamos retornar o livro criado. Segue o código abaixo:
...
/**
* Teste da rota: /GET/:id
*/
describe('/GET/:id livro', function() {
it('Deve retornar um livro dado o id', function() {
var livro = new Livro( {
titulo: "Javascript. O Guia Definitivo",
autor: "David Flanagan",
paginas:1080,
ano: 2012
});
livro.save(function(error, livro) {
chai.request(server)
.get('/livro/' + livro.id)
.send(livro)
.end(function(error, res) {
res.should.be.a('object');
res.body.should.have.property('titulo');
res.body.should.have.property('autor');
res.body.should.have.property('paginas');
res.body.should.have.property('ano');
res.body.should.have.property('_id').eql(livro.id);
done();
});
});
});
});
...
Através das afirmações criadas fez com que o servidor retorne todos os campose o livro testado com as duas ids juntas. Aqui está a saída do nosso teste:
Testando a rota /PUT/:ID
Hora de testar a atualização de um dos nossos livros. Primeiro, nós vamos salvar o livro e então atualizaremos o ano que foi publicado. Então, segue o código abaixo:
...
/**
* Teste da rota: /PUT/:id
*/
describe('/PUT/:id livro', function(){
it('Deve atualizar um livro dado o id', function(done){
var livro = new Livro({titulo: "Use A Cabeça! C#", autor: "Andrew Stellman", ano: 2013, paginas: 738})
livro.save(function(error, livro){
chai.request(server)
.put('/livro/' + livro.id)
.send({titulo: "Use A Cabeça! C#", autor: "Andrew Stellman", ano: 2014, paginas: 738})
.end(function(error, res){
res.should.have.status(200);
res.body.should.be.a('object');
res.body.should.have.property('message').eql('Livro Atualizado com Sucesso');
res.body.livro.should.have.property('ano').eql(2014);
done();
});
});
});
});
Vamos verificar se a saída está saindo de maneira corretamente:
Show de bola! 😀
Lembrando que a mensagem de retorno deve a mesmíssima que definimos lá no arquivo livro.js na pasta routes! 😀
Vamos ao nosso último teste!
Testando a rota /DELETE/:ID
O padrão é o mesmo do que do atualizar. Iremos primeiramente criar um livro e depois excluir e testar a nossa resposta. Segue o código abaixo:
...
/**
* Teste da rota: /DELETE/:id
*/
describe('/DELETE/:id livro', function(){
it('Deve excluir um livro dado o id', function(done){
var livro = new Livro({titulo: "Use A Cabeça! C#", autor: "Andrew Stellman", ano: 2013, paginas: 738})
livro.save(function(error, livro){
chai.request(server)
.delete('/livro/' + livro.id)
.end(function(error, res){
res.should.have.status(200);
res.body.should.be.a('object');
res.body.should.have.property('message').eql('Livro excluído com Sucesso!');
done();
});
});
});
});
E o resultado foi…. Sucesso! Os 6 testes que desenvolvemos estão passando sem erros!!! 😀 Excelente!
Se você chegou até aqui…..
Palavras Finais…
Esse tutorial nos deparamos com o problema de testar as nossas rotas para prover para os nossos usuários uma experiência estável.
Nós seguimos por todos os passos por criar primeiramente uma aplicação RESTFul, para que possamos realizar teste simples através do POSTMAN e claro depois desenvolver testes bem integrados que dão tão garantia do que desenvolvemos, que é justamente a razão do desenvolvimento desse tutorial.
É uma boa prática de programação sempre perder um pouco de tempo realizando e desenvolvendo testes para que possamos assegurar que o serviço está devidamente bem escrito e para evitar futuros problemas em produção.
Durante esse tutorial nós também vimos alguns benefícios de desenvolver testes e isso abrirá para tópicos mais avançados sobre Test Driven Development (TDD).
Quero agradecer a todos por acompanhar esse tutorial e quero dizer que infelizmente a empresa onde eu estava trabalhando com Node.Js me mandou embora….. enfim… se alguém estiver precisando de alguma desenvolvedora que necessite de conhecimentos em: .NET ou Node.Js, por favor entre em contato comigo AQUI.
E aqui segue o código completo desse tutorial: Código — Tutorial: AQUI
Beijos a todos e até a próxima! ❤
Originally published at code4coders.wordpress.com on October 22, 2016.