Como conectar com mongodb no node.js com TDD
Neste tutorial nós vamos ver como conectar sua aplicação Node.js com um banco de dados MongoDB. E como tem muita coisa acontecendo ao mesmo tempo, vamos trabalhar com TDL – aprendizado guiado por testes. Ou seja: vamos escrever testes para entender o que cada passo está fazendo.
Este passo a passo vai te permitir:
- Subir um banco de dados MongoDB via Docker para testes;
- Baixar e configurar o pacote mongoose;
- Criar coleções no MongoDB via mongoose;
- Inserir registros em coleções no MongoDB via mongoose; e
- Listar registros em coleções no MongoDB via mongoose
Então vem comigo que a gente vai começar!
Conteúdos do post
- Passo 1 – instalar o pacote mongoose
- Passo 2 – instalar o pacote Jest para fazer TDD
- Passo 3 – Subindo um servidor MongoDB para testes
- Passo 4 – vamos o esqueleto do nosso caso de teste
- Passo 5 – testar a conexão com o MongoDB com mongoose e jest
- Passo 6 – testar a inserção de entidades no MongoDB com mongoose e jest
- Passo 7 – testar a obtenção de documentos no MongoDB com mongoose e jest
- Código utilizado no artigo
- Recomendação de outros testes para rodar
- Conclusão
Vídeo de apoio
Caso você esteja sem energia para ler o texto, ou tenha se perdido em algum momento, eu fiz um vídeo de apoio pra te auxiliar a entender tudo sobre como começar a trabalhar com MongoDB usando Mongoose em sua aplicação node.js.
Passo 1 – instalar o pacote mongoose
Eu estou rodando o node v16.17.0
mas os passos abaixo devem funcionar bem em versões superiores à 11
sem muitos problemas.
Vamos instalar o mongoose com npm
usando a seguinte linha:
$ npm install mongoose --save
Caso você use yarn
, o comando é o seguinte:
$ yarn add mongoose
O meu package.json
ficou assim:
"dependencies": {
"mongoose": "^6.6.2"
}
Passo 2 – instalar o pacote Jest para fazer TDD
Como nós queremos trabalhar com testes, vamos instalar o pacote Jest:
$ npm install --save-dev jest
Caso você utilize o Yarn, rode o seguinte comando:
$ yarn add --dev jest
Meu package.json
ficou mais ou menos assim:
"devDependencies": {
"jest": "^29.0.3"
}
Agora vamos adicionar a seguinte seção ao arquivo package.json
:
"scripts": {
"test": "jest"
}
Com isso nós podemos rodar o seguinte comando no terminal. A cada novo arquivo que criarmos e cada vez que salvarmos um arquivo, Jest irá rodar todos os testes novamente:
$ npm run test -- --watchAll
A sua tela deverá ficar mais ou menos assim:
Deixa esse terminal rodando o comando, a gente já já vai voltar a prestar atenção nele.
Passo 3 – Subindo um servidor MongoDB para testes
Para acompanhar nosso tutorial a gente precisa de um servidor MongoDB rodando. Como eu não quero gastar tempo e energia subindo um servidor na minha máquina local, eu vou utilizar a imagem docker oficial do MongoDB.
Esta imagem exige duas variáveis de ambiente definidas:
- MONGO_INITDB_ROOT_USERNAME – o usuário padrão do banco de dados
- MONGO_INITDB_ROOT_PASSWORD – a senha do usuário padrão
Então vamos criar um arquivo .env
com o seguinte conteúdo:
MONGO_INITDB_ROOT_USERNAME=root
MONGO_INITDB_ROOT_PASSWORD=root
Com o arquivo acima criado, podemos iniciar o servidor docker com o seguinte comando:
$ docker run --rm -it --env-file .env -p27017:27017 mongo:latest
Deixa eu explicar o que comando acima está fazendo, item a item:
A opção --rm
vai apagar o container docker assim que interrompermos sua execução. Dessa forma o container não fica em disco quando a gente terminar nosso teste.
A opção -it
vai manter o shell conectado à saída do servidor, desta forma você consegue ver os logs do servidor em seu terminar. Como na imagem a seguir:
A opção --env-file .env
vai usar o arquivo .env
que nós criamos para definir as variáveis de ambiente que ficam presentes no container docker. Como nós definimos MONGO_INITDB_ROOT_USERNAME
e MONGO_INITDB_ROOT_PASSWORD
o container vai inicializar o servidor utilizando aqueles dados como usuário e senha padrão do banco de dados.
Por fim, -p27017:27017
vai mapear a porta 27017
do container à porta 27017
da máquina local. A porta 27017
é a porta padrão de conexão com o MongoDB. Ao fazer este mapeamento nós podemos acessar mongodb://localhost:27017
e o docker vai automaticamente nos rotear para o container.
O último argumento, mongo:latest
, é o nome da imagem MongoDB no Docker Hub.
Passo 4 – vamos o esqueleto do nosso caso de teste
Agora é hora de colocar a mão na massa, vamos criar nosso caso de teste para testar nossa conexão com o MongoDB.
Adicione o seguinte esqueleto num arquivo mongodb.test.js
:
// mongodb.test.js
const mongoose = require('mongoose')
test('Meu primeiro teste', () => {
expect(true).toBeTruthy()
})
Ao salvar o arquivo acima, o terminal que nós deixamos rodando desde o passo 2 deverá ficar assim:
Nosso ambiente está pronto para experimentarmos com o Mongoose!
Passo 5 – testar a conexão com o MongoDB com mongoose e jest
Vamos começar por conectar com o MongoDB usando o mongoose. De acordo com a documentação oficial nós podemos usar o método mongoose.connect(), que retorna uma Promise.
Portanto o callback da função then()
pode fazer nosso teste passar, e o callback da função catch()
deverá fazer o teste falhar. Assim nós saberemos se a conexão está funcionando.
Vamos adicionar o seguinte caso de teste:
const MONGODB_DSN = 'mongodb://root:root@localhost:27017'
test('Conexão com MongoDB', async () => {
const promise = mongoose.connect(MONGODB_DSN)
await expect(promise).resolves.toBeInstanceOf(mongoose.Mongoose)
await mongoose.connection.close()
})
Ao salvar o arquivo com o teste acima, o Jest deverá imediatamente rodar os testes e acusar sucesso (caso os dados da conexão estejam corretos):
Aproveite e mude os valores da constante MONGODB_DSN
para ter certeza de que o teste falha como deveria.
Agora vamos brincar com alguns schemas. Tá na hora de inserir uma entidade no nosso MongoDB.
Passo 6 – testar a inserção de entidades no MongoDB com mongoose e jest
É isso, vamos então criar uma coleção chamada artigos
que possui os seguintes campos:
- Título
- URL
De acordo com a documentação oficial do Mongoose nós precisamos primeiro definir um objeto do tipo Schema
, que mapeia o que acontece dentro do MongoDB para JavaScript. Depois nós precisamos criar um objeto do tipo Model
para poder interagir com aquela coleção que definimos o Schema
.
Ao inserir um objeto na coleção a gente sabe que tudo funcionou porque o mongoose vai adicionar um campo _id
do tipo mongoose.Types.ObjectId
.
Note que vamos definir Schema e Model fora do caso de teste, para que possamos reutilizar estas variáveis em outros casos de teste.
O caso de teste ficou assim:
const artigoSchema = new mongoose.Schema({
titulo: String,
url: String,
})
// 'Artigo' vai ser tratado como uma classe de agora em diante
const Artigo = mongoose.model('artigos', artigoSchema)
test('Inserção no MongoDB', async () => {
// Nós já vimos que a linha abaixo conecta ao DB
await mongoose.connect(MONGODB_DSN)
// Cria o schema que mapeia mongodb para o JS
const artigoSchema = new mongoose.Schema({
titulo: String,
url: String,
})
// 'Artigo' vai ser tratado como uma classe de agora em diante
const Artigo = mongoose.model('artigos', artigoSchema)
// Criamos uma instância de Artigo
const tutorial_mongodb = new Artigo({
titulo: 'Como conectar com mongodb no node.js com TDD',
url: 'https://codamos.com.br/como-conectar-mongodb-nodejs-tdd',
})
// Salva o registro no MongoDB
await tutorial_mongodb.save()
// 'tutorial_mongodb' agora deverá ter um campo '_id'
expect(tutorial_mongodb._id).toBeInstanceOf(mongoose.Types.ObjectId)
await mongoose.connection.close()
})
A tela do terminal do Jest ficou assim pra mim:
Passo 7 – testar a obtenção de documentos no MongoDB com mongoose e jest
Sempre que precisamos buscar um documento em nossa coleção, ou mesmo listar todos documentos, podemos utilizar o método Model.find() que deverá retornar o tipo Promise<Model[]>
.
Então para o nosso teste podemos só verificar que a lista de documentos tem mais do que 0
elementos. Afinal o teste anterior já criou documentos no banco de dados.
Um teste de produção não deveria assumir que os testes anteriores passaram, e muito menos depender de estado global. Neste caso tudo bem trabalhar assim porque estamos utilizando testes para aprender.
O caso de testes ficou assim:
test('Listar todos documentos no MongoDB', async () => {
await mongoose.connect(MONGODB_DSN)
const artigoSchema = new mongoose.Schema({
titulo: String,
url: String,
})
const artigosEncontrados = await Artigo.find()
expect(artigosEncontrados.length).toBeGreaterThan(0)
await mongoose.connection.close()
})
Jest deverá então acusar sucesso: nosso teste passou e temos uma lista de artigos na variável artigosEncontrados
.
Você também pode experimentar fazer alguns console.log()
dentro do escopo dos testes pra ver o que está lá dentro. O bacana de usar TDL é que temos um ambiente preparado para brincar e testar o que quisermos a qualquer momento, num ambiente controlado.
Código utilizado no artigo
Você pode verificar o código completo utilizado neste artigo neste GIST aqui.
Recomendação de outros testes para rodar
Você provavelmente já entendeu a ideia do negócio: cada funcionalidade que quiser testar, basta criar um novo caso de teste e ver como o framework se comporta.
Eu recomendo que você implemente por si os seguintes casos de teste:
- Atualizar um documento MongoDB;
- Buscar um documento pelo título;
- Remover um documento por
_id
; - Receber a quantidade (
count
) de documentos que atendem a um filtro; - Listar documentos ordenados por
url
Você vai ver que após escrever os testes acima, você já sabe tudo o que precisa pra começar a escrever uma aplicação completa usando Node.js, MongoDB e Mongoose.
Conclusão
Os testes que escrevemos aqui não devem ser utilizados em produção! São apenas testes que utilizamos para aprender a ferramenta. Assim que entender como a ferramenta funciona, recomendo remover estes testes e desenvolver sua aplicação de forma independente, com testes que façam sentido para a sua aplicação.
Não se esqueça de que ao interromper seu comando docker
o banco de dados não vai mais funcionar. E ao rodar o mesmo comando novamente, seu banco de dados estará vazio porque usamos a opção --rm
.
Se você gostou da forma como o artigo foi organizado, não deixa de compartilhar em suas redes sociais!
Comentários