Uma introdução
EU SEI QUE NÃO PARECE COMIGO!
give-me bitcoins!
O que são?
Onde vivem?
O que fazem?
Como se alimentam?
- 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
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.
"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."
É 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.
Cada roda deve conseguir rodar
As rodas frontais precisam virar
Cada roda deve aguentar 1/4 do peso
Imagine que seu time está desenvolvendo uma catapulta
O que são?
Onde vivem?
O que fazem?
Como se alimentam?
Mocks são funções/classes que simulam a execução de uma outra função/classe
$ npm i -g mocha
$ npm i --save-dev chai
$ mocha NOME_ARQUIVO_TESTE
(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])
)
})
E quando você tem aquele sistema gigantesco, cheio de acessos a bancos de dados e APIs externas?
com SinonJS
$ npm install --save-dev sinon
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;
});
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' }
(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}` )
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
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
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
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
Gerar coverage dos seus testes
$ npm install --save-dev nyc
$ nyc mocha ...