Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Escrevendo javascript testável

Escrevendo javascript testável

Javascript é uma linguagem incrível com um ecossistema enorme, é flexível, dinâmica, multiparadigma, mas com grandes poderes vem grandes responsabilidades e um código antes simples pode tomar proporções desconhecidas e muito confusas.

Vamos conversar sobre ferramentas e técnicas para tornam a escrita de testes uma atividade simples e prazerosa, deixando no passado aquele código macarrônico que dá medo de colocar a mão.

Avatar for Marcus Ortense

Marcus Ortense

July 21, 2018
Tweet

More Decks by Marcus Ortense

Other Decks in Technology

Transcript

  1. Testes de Interface (Workflows/ Lógica de Negócio/ Visual Regression) 2

    Testes Unitários e Componentes 4 Testes de API/Serviço (Regras de Negócio/Funcionais) 3 Testes Manuais e Exploratórios 1 ENTENDENDO OS TESTES
  2. Testes de API/Serviço (Regras de Negócio/Funcionais) 3 Testes de Interface

    (Workflows/ Lógica de Negócio/ Visual Regression) 2 Testes Unitários e Componentes 4 Testes Manuais e Exploratórios 1 ENTENDENDO OS TESTES
  3. Testes de Interface (Workflows/ Lógica de Negócio/ Visual Regression) 2

    Testes Unitários e Componentes 4 Testes de API/Serviço (Regras de Negócio/Funcionais) 3 Testes Manuais e Exploratórios 1 ENTENDENDO OS TESTES
  4. app.post('/users', async (req, res) => { if (!req.body.login) return res.status(401).json({

    error: 'login is required' }) const user = await mongo.collection('users') .insertOne(req.body).then(result => result.ops[0]) return res.status(201).json(user) })
  5. app.post('/users', async (req, res) => { if (!req.body.login) return res.status(401).json({

    error: 'login is required' }) const user = await mongo.collection('users') .insertOne(req.body).then(result => result.ops[0]) return res.status(201).json(user) })
  6. app.post('/users', async (req, res) => { if (!req.body.login) return res.status(401).json({

    error: 'login is required' }) const user = await mongo.collection('users') .insertOne(req.body).then(result => result.ops[0]) return res.status(201).json(user) })
  7. app.post('/users', async (req, res) => { if (!req.body.login) return res.status(401).json({

    error: 'login is required' }) const user = await mongo.collection('users') .insertOne(req.body).then(result => result.ops[0]) return res.status(201).json(user) })
  8. app.post('/users', async (req, res) => { if (!req.body.login) return res.status(401).json({

    error: 'login is required' }) if (!req.body.password) return res.status(401).json({ error: 'password is required' }) const user = await mongo.collection('users') .insertOne(req.body).then(result => result.ops[0]) return res.status(201).json(user) })
  9. app.post('/users', async (req, res) => { try { if (!req.body.login)

    return res.status(401).json({ error: 'login is required' }) if (!req.body.password) return res.status(401).json({ error: 'password is required' }) const user = await mongo.collection('users') .insertOne(req.body).then(result => result.ops[0]) return res.status(201).json(user) } catch(err) { console.error(err) return res.status(500).json({ error: 'unexpected internal error' }) } })
  10. app.post('/users', async (req, res) => { try { const emailRgx

    = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w+)+$/ if (!req.body.login) return res.status(401).json({ error: 'login is required' }) if (!emailRgx.test(req.body.login)) return res.status(401).json({ error: 'your login must be a valid email' }) if (!req.body.password) return res.status(401).json({ error: 'password is required' }) const user = await mongo.collection('users').insertOne(req.body).then(result => result.ops[0]) return res.status(201).json(user) } catch(err) { console.error(err) return res.status(500).json({error: 'unexpected internal error' }) } })
  11. app.post('/users', async (req, res) => { try { const emailRgx

    = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w+)+$/ if (!req.body.login) return res.status(401).json({ error: 'login is required' }) if (!emailRgx.test(req.body.login)) return res.status(401).json({ error: 'your login must be a valid email' }) if (!req.body.password) return res.status(401).json({ error: 'password is required' }) const user = await mongo.collection('users').insertOne(req.body).then(result => result.ops[0]) .catch(err => { console.error(err) return null }) return user ? res.status(201).json(user) : res.status(500).json({ error: 'unexpected internal error' }) } catch(err) { console.error(err) return res.status(500).json({error: 'unexpected internal error' }) } })
  12. app.post('/users', async (req, res) => { try { const emailRgx

    = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w+)+$/ if (!req.body.login) return res.status(401).json({ error: 'login is required' }) if (!emailRgx.test(req.body.login)) return res.status(401).json({ error: 'your login must be a valid email' }) if (!req.body.password) return res.status(401).json({ error: 'password is required' }) const user = await mongo.collection('users').insertOne(req.body).then(result => result.ops[0]) .catch(err => { console.error(err) return null }) return user ? res.status(201).json(user) : res.status(500).json({ error: 'unexpected internal error' }) } catch(err) { console.error(err) return res.status(500).json({error: 'unexpected internal error' }) } })
  13. project ├── product ├── index.js ├── product.js └── product.routes.js ├──

    user ├── index.js ├── user.js └── user.routes.js └── shared/ ... project ├── controllers ├── product.js └── user.js ├── models ├── product.js └── user.js ├── routes ├── product.js └── user.js
  14. let value = 0 const increment = () => value

    += 1 increment() // 1 increment() // 2
  15. let value = 0 const increment = value => value

    + 1 increment(value) // 1 increment(value) // 1
  16. let value = 0 const increment = value => value

    + 1 value = increment(value) // 1 value = increment(value) // 2
  17. let value = 0 export const increment = value =>

    value + 1 value = increment(value) // 1 value = increment(value) // 2
  18. import { increment } from './calc' test('increment', () => {

    expect(increment(-1)).toBe(0) expect(increment(0)).toBe(1) expect(increment(1)).toBe(2) })
  19. import { increment } from './calc' test('increment', () => {

    expect(increment(-1)).toBe(0) expect(increment(0)).toBe(1) expect(increment(1)).toBe(2) })
  20. import { increment } from './calc' test('increment', () => {

    expect(increment(-1)).toBe(0) expect(increment(0)).toBe(1) expect(increment(1)).toBe(2) })
  21. test('.getByID', async () => { const response = { json:

    jest.fn() } const request = jest.fn().mockResolvedValue(response) await myModule.getByID('123', request) expect(request).toBeCalledWith('/end/point/123') expect(response.json).toHaveBeenCalled() })
  22. test('.getByID', async () => { const response = { json:

    jest.fn() } const request = jest.fn().mockResolvedValue(response) await myModule.getByID('123', request) expect(request).toBeCalledWith('/end/point/123') expect(response.json).toHaveBeenCalled() })
  23. test('.getByID', async () => { const response = { json:

    jest.fn() } const request = jest.fn().mockResolvedValue(response) await myModule.getByID('123', request) expect(request).toBeCalledWith('/end/point/123') expect(response.json).toHaveBeenCalled() })
  24. test('.getByID', async () => { const response = { json:

    jest.fn() } const request = jest.fn().mockResolvedValue(response) await myModule.getByID('123', request) expect(request).toBeCalledWith('/end/point/123') expect(response.json).toHaveBeenCalled() })
  25. export const createMyModule = ({ request }) => ({ getByID(id)

    { return request(`/end/point/${id}`) .then(response => response.json()) } })
  26. export const createMyModule = ({ request }) => ({ getByID(id)

    { return request(`/end/point/${id}`) .then(response => response.json()) } })
  27. test('.getByID', async () => { const request = jest.fn() const

    myModule = createMyModule({ request }) await myModule.getByID('123') expect(request).toBeCalledWith('/end/point/123') })
  28. test('.getByID', async () => { const request = jest.fn() const

    myModule = createMyModule({ request }) await myModule.getByID('123') expect(request).toBeCalledWith('/end/point/123') })
  29. export class MyModule { constructor (dependencies) { this.request = dependencies.request

    } getByID(id) { return this.request(`/end/point/${id}`) .then(response => response.json()) } }
  30. export class MyModule { constructor (dependencies) { this.request = dependencies.request

    } getByID(id) { return this.request(`/end/point/${id}`) .then(response => response.json()) } }
  31. test('.getByID', async () => { const request = jest.fn() const

    myModule = new MyModule({ request }) await myModule.getByID('123') expect(request).toBeCalledWith('/end/point/123') })
  32. test('.getByID', async () => { const request = jest.fn() const

    myModule = new MyModule({ request }) await myModule.getByID('123') expect(request).toBeCalledWith('/end/point/123') })
  33. CONCLUINDO ✓ Isole a responsabilidade do código ✓ Funções pequenas

    e puras são mais fáceis de testar ✓ A injeção de dependência é sua amiga ✓ Use gifs!