Testes e Mocks

em NodeJS

Uma introdução

# whoami

root Victor Perin

  • 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!

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

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

Outros tipos de teste

Mocks

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

Testes em NodeJS

$ 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?

Mocks em NodeJS

com SinonJS

  • 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}` )

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

$ npm install --save-dev nyc

$ nyc mocha ...

Testes e Mocks em NodeJS

By Victor Perin

Testes e Mocks em NodeJS

  • 716