Testes e Mocks
em NodeJS
Uma introdução
# whoami
root Victor Perin
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/3591249/pasted-from-clipboard.png)
- Organizador do NodeSchool Campinas
- Desenvolvedor NodeJS na InGaia
- Tapa buraco de Talks (MANDEM TALKS!)
- ❤️ Criptografia / Privacidade / Bitcoins
- ❤️ JS / Docker / NoSQL
- ❤️ Testes / Clean Code / Craftsmanship
- ❤️ Functional Programming / Async
EU SEI QUE NÃO PARECE COMIGO!
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/3797901/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4134273/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/3797901/pasted-from-clipboard.png)
give-me bitcoins!
Testes
O que são?
Onde vivem?
O que fazem?
Como se alimentam?
O que são?
Testes são formas de verificar se uma parte do seu código está/continua funcionado.
Por que devo testar?
- Como saber se seu código funciona? Fácil, teste-o.
- Mas vou gastar muito tempo!
- Então Automatize-os.
Por que a maioria dos desenvolvedores teme fazer mudanças contínuas no código?
Eles tem medo de quebrá-lo! Por quê? Porque eles não fazem testes.
Livro: O Codificador Limpo
Uncle Bob
Debug efetivo de Código
If you're good at the debugger it means you spent a lot of time debugging. I don't want you to be good at the debugger.
Uncle Bob
Quando um sistema está bem testado, você não precisa passar horas navegando pelo debugger.
Exemplos
"Nova versão do ${YOUR_FRAMEWORK_HERE} saiu. E agora?"
Product Owner: "Essa feature não era bem assim que expliquei"
"Mas funciona na minha maquina"
"Deploy de sexta-feira?!"
"Não da mais pra continuar, vamos ter que reescrever."
Opinião do Perin
É obrigação do desenvolvedor entregar um software que funciona.
Como você sabe se está funcionando? Testando.
De forma manual ou automatizada.
Por isso, é sua DEVER, como profissional, criar testes para que você tenha certeza de que o software que você escreveu vai continuar funcionando no futuro.
Tipos de testes
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4132361/1-UtZzMT32fRMnSN-HmgiSVQ.gif)
Unitários
- Testam as menores unidades do sistema. (Funções, Classes, etc)
- São os tipos mais simples.
- TDD é aqui!
- Devem rodar rápido
- Devem ser independentes
Integração
- Testam interação de unidades.
- São um pouco mais complexos.
- Devem ser independentes!
Unitários
-
Cada roda deve conseguir rodar
-
As rodas frontais precisam virar
-
Cada roda deve aguentar 1/4 do peso
Integração
- A catapulta tem que andar
- A catapulta tem que girar
- As rodas devem aguentar o peso
Um exemplo:
Imagine que seu time está desenvolvendo uma catapulta
Piramide de Testes
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4134080/Untitled-drawing-1.png)
Outros tipos de teste
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4133818/pasted-from-clipboard.png)
Mocks
O que são?
Onde vivem?
O que fazem?
Como se alimentam?
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4133848/pasted-from-clipboard.png)
Mocks são funções/classes que simulam a execução de uma outra função/classe
Testes em NodeJS
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4134086/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4134097/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4134098/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4134099/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4134102/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4134104/pasted-from-clipboard.png)
$ npm i -g mocha
$ npm i --save-dev chai
$ mocha NOME_ARQUIVO_TESTE
Hello World
(Usando Mocha + Chai)
// say-hello.test.js
require('chai').should()
describe('sayHello', () => {
const sayHello = require('./say-hello')
it('should match exactly with hello and a name', () =>
sayHello('perin').should.equal('hello perin')
)
})
// say-hello.js
module.exports =
(name) =>
`Hello ${name}`
it('should contain the name on response (single)', () =>
sayHello('joão').should.include('joão')
)
it('should contain the word hello', () =>
sayHello('maria').should.include('hello')
)
it('should contain the name on response', () => {
const names = ['joão', 'maria', 'Jonisvaldo']
const responses = names.map( sayHello )
responses.forEach( (response, index) =>
response.should.include(names[index])
)
})
Mas...
E quando você tem aquele sistema gigantesco, cheio de acessos a bancos de dados e APIs externas?
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4134226/giphy__3_.gif)
Mocks em NodeJS
com SinonJS
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4134236/pasted-from-clipboard.png)
- Spies
- Stubs
- Mocks
- Fake timers
- Fake XHR and server
- etc...
$ npm install --save-dev sinon
Spies
Use no lugar de callbacks, por exemplo
PS: injeção de dependência! o/
it("should call subscribers on publish", () => {
const callback = sinon.spy();
PubSub.subscribe("message", callback);
PubSub.publishSync("message");
callback.called.should.be.true;
});
Mocks and Expectations
Quando você não tem controle na definição
const jQueryMock = sinon.mock(jQuery)
const ajaxExpectation = jQuery.expects("ajax")
.returns({ data: 'huehue' })
jQuery.ajax() // { data: 'huehue' }
Hello World (Database)
(Usando Mocha + Chai + Sinon)
it('should find the name in userDb', () => {
const userDbMock = sinon.mock(userDb)
userDbMock
.expects('find')
.resolves({ name: 'perin' })
sayHello('perin')
.should.equal('hello perin')
userDbMock.restore()
})
// say-hello.js
const userDb = require('./some-db-user')
module.exports =
(id) =>
userDb
.find(id)
.then( ({name}) => `Hello ${name}` )
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4134288/giphy__4_.gif)
Outras ferramentas
Supertest
Teste requests HTTP, sem necessariamente precisar subir seu sistema.
const request = require('supertest');
const express = require('express');
const app = express();
app.get('/user', function(req, res) {
res.status(200).json({ name: 'tobi' });
});
request(app)
.get('/user')
.expect('Content-Type', /json/)
.expect('Content-Length', '15')
.expect(200)
.then(console.log);
$ npm install --save-dev supertest
Mockgoose
Sobe um servidor mongodb in-memory para testes
const Mongoose = require('mongoose').Mongoose;
const mongoose = new Mongoose();
const Mockgoose = require('mockgoose').Mockgoose;
const mockgoose = new Mockgoose(mongoose);
before( () =>
mockgoose
.prepareStorage()
.then( () => mongoose.connect('mongodb://example.com/TestingDB') );
);
$ npm install --save-dev mockgoose
Knex-mock
Igual ao mockgoose, mas com bancos sql
const knex = require('knex');
const mockDb = require('mock-knex');
const db = knex({
client: 'sqlite',
});
beforeEach( () => mockDb.mock(db) );
afterEach( () => mockDb.unmock(db) );
$ npm install --save-dev knex-mock
mock-fs
Faça mock de pastas e arquivos
var mock = require('mock-fs');
mock({
'path/to/fake/dir': {
'some-file.txt': 'file content here',
'empty-dir': {/** empty directory */}
},
'path/to/some.png': new Buffer([8, 6, 7, 5, 3, 0, 9]),
'some/other/path': {/** another empty directory */}
});
mock.restore();
$ npm install --save-dev mock-fs
IstanbulJS (nyc)
Gerar coverage dos seus testes
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4135730/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4135733/pasted-from-clipboard.png)
$ npm install --save-dev nyc
$ nyc mocha ...
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4134296/giphy__5_.gif)
Testes e Mocks em NodeJS
By Victor Perin
Testes e Mocks em NodeJS
- 716