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

[Trem on Rails] Como não odiar seus testes

[Trem on Rails] Como não odiar seus testes

Sabemos que escrever testes automatizados é extremamente importante, pois, entre outras coisas, eles garantem a qualidade do nosso código e o funcionamento da nossa aplicação. Apesar disso, muitas vezes acabamos com uma suíte de testes que, além de ser difícil de entender e manter, não é confiável. Nessa talk, vamos ver como reconhecer e evitar alguns dos problemas mais comuns que nos fazem odiar nossos testes, além de dar algumas dicas de como melhorar nossos testes.

Links legais:
Talk: Como não odiar seus testes (v1): https://www.youtube.com/watch?v=Dkqbck_DMoE&ab_channel=AtlasTechnologies
Livro: X-Unit Patterns: http://xunitpatterns.com/
Catálogo de test smells: https://test-smell-catalog.readthedocs.io/
Talk do Joe Yoder: Architecting Agility: https://www.youtube.com/live/0bGVSQw1948?si=7Hn3F9KDa_vhpxJs&t=2634

Avatar for Camila Campos

Camila Campos

August 16, 2025
Tweet

More Decks by Camila Campos

Other Decks in Programming

Transcript

  1. @camposmilaa Camila Campos Meu propósito de vida é promover diversidade

    e inclusão através da educação @camposmilaa Software Engineer @ Coinbase
  2. @camposmilaa test('should setup middleware', async () => { const nuxt

    = createNuxt() const server = new Server(nuxt) server.useMiddleware = jest.fn() server.serverContext = { id: 'test-server-context' } await server.setupMiddleware() expect(server.nuxt.callHook).toBeCalledTimes(2) expect(server.nuxt.callHook).nthCalledWith(1, 'render:setupMiddleware', server.app) expect(server.nuxt.callHook).nthCalledWith(2, 'render:errorMiddleware', server.app) expect(server.useMiddleware).toBeCalledTimes(4) expect(serveStatic).toBeCalledTimes(2) expect(serveStatic).nthCalledWith(1, 'resolve(/var/nuxt/src, var/nuxt/static)', server.options.render.static) expect(server.useMiddleware).nthCalledWith(1, { dir: 'resolve(/var/nuxt/src, var/nuxt/static)', id: 'test-serve-static', prefix: 'test-render-static-prefix' }) expect(serveStatic).nthCalledWith(2, 'resolve(/var/nuxt/build, dist, client)', server.options.render.dist) expect(server.useMiddleware).nthCalledWith(2, { handler: { dir: 'resolve(/var/nuxt/build, dist, client)', id: 'test-serve-static' }, path: '__nuxt_test' }) const nuxtMiddlewareOpts = { options: server.options, nuxt: server.nuxt, renderRoute: expect.any(Function), resources: server.resources } expect(nuxtMiddleware).toBeCalledTimes(1) expect(nuxtMiddleware).toBeCalledWith(nuxtMiddlewareOpts)
  3. @camposmilaa @camposmilaa Tempo Sentido Demora muito pra rodar Gasta tempo

    para fazer Não dá pra entender Não testa nada Falha aleatoriamente É redundante
  4. @camposmilaa Code without tests is bad code. It doesn’t matter

    how well written it is; it doesn’t matter how pretty or object-oriented or well-encapsulated it is. (...) Michael Feathers
  5. @camposmilaa Código sem testes é código ruim. Não importa o

    quão bem escrito está; não importa quão bonito ou orientado a objetos ou bem encapsulado ele está. (...) Michael Feathers
  6. @camposmilaa @camposmilaa Testes não são só sobre achar bugs na

    aplicação! Achar bugs Poder mudar comportamento Evitar bugs Ter qualidade de código Poder refatorar Ter uma boa arquitetura Garantir funcionamento Mover com agilidade
  7. @camposmilaa "Escrever testes gasta um tempo precioso do time de

    desenvolvimento, que poderia estar sendo usado para fazer funcionalidades!"
  8. @camposmilaa @camposmilaa se você acha que uma boa arquitetura custa

    caro, tenta ter uma arquitetura ruim. Joe Yoder
  9. @camposmilaa Hora de refatorar! Setup complexo ou grande Múltiplas verificações

    Fluxo de teste muito longo Muitas dependências Muitas responsabilidades
  10. @camposmilaa Hora de refatorar! Setup complexo ou grande Múltiplas verificações

    Fluxo de teste muito longo Muitas dependências Muitas responsabilidades API complexa
  11. @camposmilaa Hora de refatorar! Setup complexo ou grande Múltiplas verificações

    Código complexo no teste Fluxo de teste muito longo Muitas dependências Muitas responsabilidades API complexa
  12. @camposmilaa Hora de refatorar! Muitos passos de "exercise" Setup complexo

    ou grande Múltiplas verificações Código complexo no teste Fluxo de teste muito longo Muitas dependências Muitas responsabilidades Código complexo API complexa
  13. @camposmilaa @camposmilaa "Tem um tanto de testes na minha aplicação,

    mas eles demoram horas para rodar. Haja paciencia! ):"
  14. @camposmilaa @camposmilaa testes de unidade Não é teste de unidade

    se: 1. Não é rápido 2. Fala com o banco de dados 3. Faz chamadas externas 4. Escreve/Lê algum arquivo 5. Precisa de configurações especiais de ambiente
  15. @camposmilaa "Que que tá rolando nesse teste?" "Essa desgrama não

    tá testando é nada!" "Roda de novo que vai…"
  16. @camposmilaa "Every piece of knowledge must have a single, unambiguous,

    authoritative representation within a system" Andy Hunt e Dave Thomas - The Pragmatic Programmer
  17. @camposmilaa "Cada pedaço de conhecimento deve ter uma representação única,

    clara e confiável dentro do sistema." Andy Hunt e Dave Thomas - The Pragmatic Programmer
  18. @camposmilaa it 'greets a person' do # ... end it

    'gracefully greets a person' do # ... end
  19. @camposmilaa it 'greets a person' do person = Person.new(name: 'any-name')

    response = Messenger.new(person).greet expect(response).to eq 'Hello, any-name' end it 'gracefully greets a person' do person = Person.new(name: 'any-name') response = Messenger.new(person).fancy_greet expect(response).to eq "Good afternoon, ma'am any-name!" end
  20. @camposmilaa it 'greets a person' do person = Person.new(name: 'any-name')

    response = Messenger.new(person).greet expect(response).to eq 'Hello, any-name' end it 'gracefully greets a person' do person = Person.new(name: 'any-name') response = Messenger.new(person).fancy_greet expect(response).to eq "Good afternoon, ma'am any-name!" end
  21. @camposmilaa it 'greets a person' do person = Person.new(name: 'any-name')

    response = Messenger.new(person).greet expect(response).to eq 'Hello, any-name' end it 'gracefully greets a person' do person = Person.new(name: 'any-name') response = Messenger.new(person).fancy_greet expect(response).to eq "Good afternoon, ma'am any-name!" end
  22. @camposmilaa it 'greets a person' do person = Person.new(name: 'any-name')

    response = Messenger.new(person).greet expect(response).to eq 'Hello, any-name' end it 'gracefully greets a person' do person = Person.new(name: 'any-name') response = Messenger.new(person).fancy_greet expect(response).to eq "Good afternoon, ma'am any-name!" end
  23. @camposmilaa it 'greets a person' do person = Person.new(name: 'any-name')

    response = Messenger.new(person).greet expect(response).to eq 'Hello, any-name' end it 'gracefully greets a person' do person = Person.new(name: 'any-name') response = Messenger.new(person).fancy_greet expect(response).to eq "Good afternoon, ma'am any-name!" end
  24. @camposmilaa let(:person) { Person.new(name: 'any-name') } it 'greets a person'

    do response = Messenger.new(person).greet expect(response).to eq 'Hello, any-name' end it 'gracefully greets a person' do response = Messenger.new(person).fancy_greet expect(response).to eq "Good afternoon, ma'am any-name!" end
  25. @camposmilaa let(:person) { Person.new(name: 'any-name') } it 'greets a person'

    do response = Messenger.new(person).greet expect(response).to eq 'Hello, any-name' end it 'gracefully greets a person' do response = Messenger.new(person).fancy_greet expect(response).to eq "Good afternoon, ma'am any-name!" end
  26. @camposmilaa let(:person) { Person.new(name: 'any-name') } let(:messenger) { Messenger.new(person) }

    it 'greets a person' do expect(messenger.greet).to eq 'Hello, any-name' end it 'gracefully greets a person' do expect(messenger.fancy_greet).to eq "Good afternoon, ma'am any-name!" end
  27. @camposmilaa let(:person) { Person.new(name: 'any-name') } let(:messenger) { Messenger.new(person) }

    it 'greets a person' do expect(messenger.greet).to eq 'Hello, any-name' end it 'gracefully greets a person' do expect(messenger.fancy_greet).to eq "Good afternoon, ma'am any-name!" end
  28. @camposmilaa let(:person) { Person.new(name: 'any-name') } let(:messenger) { Messenger.new(person) }

    it 'greets a person' do expect(messenger.greet).to eq 'Hello, any-name' end it 'gracefully greets a person' do expect(messenger.fancy_greet).to eq "Good afternoon, ma'am any-name!" end
  29. @camposmilaa let(:person) { Person.new(name: 'any-name') } let(:messenger) { Messenger.new(person) }

    it 'greets a person' do expect(messenger.greet).to eq "Hello, #{person.name}" end it 'gracefully greets a person' do expect(messenger.fancy_greet).to eq "Good afternoon, ma'am #{person.name}!" end
  30. @camposmilaa let(:person) { Person.new(name: 'any-name') } let(:messenger) { Messenger.new(person) }

    it 'does an entirely different thing' do # .... end it 'greets a person' do expect(messenger.greet).to eq "Hello, #{person.name}" end it 'gracefully greets a person' do expect(messenger.fancy_greet).to eq "Good afternoon, ma'am #{person.name}!" end
  31. @camposmilaa let(:person) { Person.new(name: 'any-name') } let(:messenger) { Messenger.new(person) }

    it 'does nothing sometimes' do # .... end it 'does an entirely different thing' do # .... end it 'greets a person' do expect(messenger.greet).to eq "Hello, #{person.name}" end it 'gracefully greets a person' do expect(messenger.fancy_greet).to eq "Good afternoon, ma'am #{person.name}!" end
  32. @camposmilaa let(:person) { Person.new(name: 'any-name') } let(:messenger) { Messenger.new(person) }

    it 'does any other thing' do # .... end it 'does nothing sometimes' do # .... end it 'does an entirely different thing' do # .... end it 'greets a person' do expect(messenger.greet).to eq "Hello, #{person.name}" end it 'gracefully greets a person' do expect(messenger.fancy_greet).to eq "Good afternoon, ma'am #{person.name}!" end
  33. @camposmilaa let(:person) { Person.new(name: 'any-name') } let(:messenger) { Messenger.new(person) }

    it 'does something else' do # .... end it 'does any other thing' do # .... end it 'does nothing sometimes' do # .... end it 'does an entirely different thing' do # .... end it 'greets a person' do expect(messenger.greet).to eq "Hello, #{person.name}" end it 'gracefully greets a person' do expect(messenger.fancy_greet).to eq "Good afternoon, ma'am #{person.name}!" end
  34. @camposmilaa let(:person) { Person.new(name: 'any-name') } let(:messenger) { Messenger.new(person) }

    it 'does something' do # .... end it 'does something else' do # .... end it 'does any other thing' do # .... end it 'does nothing sometimes' do # .... end it 'does an entirely different thing' do # .... end it 'greets a person' do expect(messenger.greet).to eq "Hello, #{person.name}" end it 'gracefully greets a person' do expect(messenger.fancy_greet).to eq "Good afternoon, ma'am #{person.name}!" end
  35. @camposmilaa let(:person) { Person.new(name: 'any-name') } let(:messenger) { Messenger.new(person) }

    it 'does something' do # .... end it 'does something else' do # .... end it 'does any other thing' do # .... end it 'does nothing sometimes' do # .... end it 'does an entirely different thing' do # .... end it 'greets a person' do expect(messenger.greet).to eq "Hello, #{person.name}" end it 'gracefully greets a person' do expect(messenger.fancy_greet).to eq "Good afternoon, ma'am #{person.name}!" end
  36. @camposmilaa it 'greets a person' do person = Person.new(name: 'any-name')

    response = Messenger.new(person).greet expect(response).to eq 'Hello, any-name' end it 'gracefully greets a person' do person = Person.new(name: 'any-name') response = Messenger.new(person).fancy_greet expect(response).to eq "Good afternoon, ma'am any-name!" end
  37. @camposmilaa it 'greets a person' do person = Person.new(name: 'any-name')

    # Setup response = Messenger.new(person).greet # Exercise expect(response).to eq 'Hello, any-name' # Verify end
  38. @camposmilaa it 'greets a person' do person = Person.new(name: 'any-name')

    # Setup response = Messenger.new(person).greet # Exercise expect(response).to eq 'Hello, any-name' # Verify end
  39. @camposmilaa it 'greets a person' do person = Person.new(name: 'any-name')

    # Setup response = Messenger.new(person).greet # Exercise expect(response).to eq 'Hello, any-name' # Verify end
  40. @camposmilaa it 'greets a person' do person = Person.new(name: 'any-name')

    # Setup response = Messenger.new(person).greet # Exercise expect(response).to eq 'Hello, any-name' # Verify end
  41. @camposmilaa it 'greets a person' do person = Person.new(name: 'any-name')

    # Setup response = Messenger.new(person).greet # Exercise expect(response).to eq 'Hello, any-name' # Verify end
  42. @camposmilaa it 'greets a person' do person = Person.new(name: 'any-name')

    # Setup response = Messenger.new(person).greet # Exercise expect(response).to eq 'Hello, any-name' # Verify end
  43. @camposmilaa it 'sends email to person' do mailer = double('my

    mailer') # Setup person = Person.new(name: 'any-name', email: '[email protected]') # Setup expect(mailer).to receive(:notify).with(person.email) # Verify Messenger.new(person, mailer: mailer).send_email # Exercise end
  44. @camposmilaa it 'sends email to person' do mailer = double('my

    mailer') # Setup person = Person.new(name: 'any-name', email: '[email protected]') # Setup expect(mailer).to receive(:notify).with(person.email) # Verify Messenger.new(person, mailer: mailer).send_email # Exercise end
  45. @camposmilaa it 'sends email to person' do mailer = double('my

    mailer') # Setup person = Person.new(name: 'any-name', email: '[email protected]') # Setup expect(mailer).to receive(:notify).with(person.email) # Verify Messenger.new(person, mailer: mailer).send_email # Exercise end
  46. @camposmilaa it 'sends email to person' do mailer = double('my

    mailer') # Setup person = Person.new(name: 'any-name', email: '[email protected]') # Setup expect(mailer).to receive(:notify).with(person.email) # Verify Messenger.new(person, mailer: mailer).send_email # Exercise end
  47. @camposmilaa it 'sends email to person' do mailer = double('my

    mailer') # Setup person = Person.new(name: 'any-name', email: '[email protected]') # Setup expect(mailer).to receive(:notify).with(person.email) # Verify Messenger.new(person, mailer: mailer).send_email # Exercise end
  48. @camposmilaa it 'sends email to person' do mailer = double('my

    mailer') # Setup person = Person.new(name: 'any-name', email: '[email protected]') # Setup expect(mailer).to receive(:notify).with(person.email) # Verify Messenger.new(person, mailer: mailer).send_email # Exercise end
  49. @camposmilaa it 'sends email to person' do mailer = spy('my

    mailer') # Setup person = Person.new(name: 'any-name', email: '[email protected]') # Setup Messenger.new(person, mailer: mailer).send_email # Exercise expect(mailer).to have_received(:notify).with(person.email) # Verify end
  50. @camposmilaa Diminua testes redundantes controller service model repository A B

    A B A B classe 1 classe 2 classe 4 classe 3 A B A B
  51. @camposmilaa Diminua testes redundantes controller service model repository A B

    A B A B classe 1 classe 2 classe 4 classe 3 A B A B O teste é de unidade mesmo? Que tal remover alguns desses testes?
  52. @camposmilaa @camposmilaa Testes intermitentes: arrume agora ou delete! Dependentes de

    ordem Precisam de configurações externas Quebram em determinados horários Funcionam em só um tipo de máquina
  53. @camposmilaa @camposmilaa como não odiar seus testes 1. Ter bons

    testes é ter qualidade de código 2. Testes difíceis indicam código ruim 3. Um teste bom é simples e fácil de entender
  54. @camposmilaa para mais detalhes sobre test smells 1. Talk: Como

    não odiar seus testes (v1) 2. Livro: X-Unit Patterns 3. Catálogo de test smells 4. Talk do Joe Yoder: Architecting Agility
  55. @camposmilaa @camposmilaa (...) undesigned applications carry the seeds of their

    own destruction; they are easy to write but gradually become impossible to change. Sandi Metz
  56. @camposmilaa @camposmilaa (...) aplicações sem design carregam os frutos da

    sua própria destruição; elas são fáceis de escrever mas gradualmente se tornam impossíveis de mudar. Sandi Metz