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

Testando código em Python

Testando código em Python

Slides de apresentação no encontro da Python Floripa.

Elias Dorneles

December 10, 2015
Tweet

More Decks by Elias Dorneles

Other Decks in Programming

Transcript

  1. • Consigo ir mais longe • Reduz a quantidade de

    adivinhação • Por conseguinte, reduz minha ansiedade :) PORÉM: não ajuda se falta feedback para coisas mais amplas (tipo: estou criando o produto certo?) Por que é legal escrever testes?
  2. Cheap trick $ ./meu_script.py <in.txt >out.txt $ diff <(./meu_script.py <in.txt)

    out.txt Prós: 1. de graça! 2. se sentir Unıx hacker :D Contras: 1. cobre apenas o caminho feliz 2. não aponta o problema exato
  3. Suíte de testes $ cat run_tests.sh #!/bin/bash set -e diff

    <(python meu_script.py < in1.txt) out1.txt diff <(python meu_script.py < in2.txt) out2.txt diff <(python meu_script.py < in3.txt) out3.txt $ ./run_tests.sh
  4. Suíte de testes $ cat run_tests.sh #!/bin/bash set -e diff

    <(python meu_script.py < in1.txt) out1.txt diff <(python meu_script.py < in2.txt) out2.txt diff <(python meu_script.py < in3.txt) out3.txt $ ./run_tests.sh Fixtures
  5. Suíte de testes $ cat run_tests.sh #!/bin/bash set -e diff

    <(python meu_script.py < in1.txt) out1.txt diff <(python meu_script.py < in2.txt) out2.txt diff <(python meu_script.py < in3.txt) out3.txt $ ./run_tests.sh Fixtures Expectativas
  6. Suíte de testes $ cat run_tests.sh #!/bin/bash set -e diff

    <(python meu_script.py < in1.txt) out1.txt diff <(python meu_script.py < in2.txt) out2.txt diff <(python meu_script.py < in3.txt) out3.txt $ ./run_tests.sh Fixtures Expectativas Caso
  7. Suíte de testes $ cat run_tests.sh #!/bin/bash set -e diff

    <(python meu_script.py < in1.txt) out1.txt diff <(python meu_script.py < in2.txt) out2.txt diff <(python meu_script.py < in3.txt) out3.txt $ ./run_tests.sh Fixtures Expectativas Suíte Caso
  8. Estrutura de um teste ➔ Dado: ◆ fixtures, inicializando código

    a ser testado ➔ Quando: ◆ exercitar código a ser testado ➔ Então: ◆ verifica se resultado é o esperado
  9. “Show me some code!” import unittest class ExampleCase(unittest.TestCase): def test_something(self):

    # given: fixture = self.build_fixture(...) # when: resultado = codigo_a_testar(fixture) # then: self.assertEqual(esperado, resultado)
  10. Estrutura de um teste ➔ Dado: ◆ fixtures, inicializando código

    a ser testado ➔ Quando: ◆ exercitar código a ser testado ➔ Então: ◆ verifica se resultado é o esperado Parte mais chata
  11. Estrutura de um teste ➔ Dado: ◆ fixtures, inicializando código

    a ser testado ➔ Quando: ◆ exercitar código a ser testado ➔ Então: ◆ verifica se resultado é o esperado Parte mais importante e mais fácil de errar
  12. Exemplo com bug na verificação def test_device_should_be_connected(self): # when: report

    = get_status_report(self.device) # then: self.assertTrue('connected' in report)
  13. Fazendo o teste falhar def test_device_should_be_connected(self): # when: report =

    get_status_report(self.offline_device) # then: self.assertTrue('connected' in report) OOOPS! Teste continua passando!
  14. Corrigindo... def test_device_should_be_connected(self): # when: report = get_status_report(self.offline_device) # then:

    self.assertRegexpMatches(report, r'\bconnected') Agora o teste falha, como esperado
  15. Tipos de dublês de teste ➔ Dummy ◆ só para

    preencher argumentos (geralmente vazios, tipo None, [], {}, etc) ➔ Fakes ◆ implementação leve duma dependência (exemplo: DB em memória) ➔ Stubs ◆ simulam respostas prontas para chamadas feitas pelo código sendo testado ➔ Mocks ◆ especificam contrato com código sendo testado (possuem asserções)
  16. Context managers ajudam com captura/cleanup @contextmanager def script_args(argv): old_argv =

    sys.argv try: sys.argv = ['fake_script.py'] + argv yield sys.argv finally: sys.argv = old_argv
  17. Context managers ajudam com captura/cleanup # USANDO: with script_args(['--opcao1', '--opcao2']):

    print(sys.argv) # vai mostrar: # ['fake_script.py', '--opcao1', '--opcao2']
  18. Mais ferramentas legais • VCR.py https://pypi.python.org/pypi/vcrpy • Tox: https://tox.readthedocs.org •

    py.test http://pytest.org/ • Nose: https://nose.readthedocs.org Wishlist: RSpec para Python (http://rspec.info)
  19. Últimos pensamentos... • Testar a coisa certa, na camada correta,

    às vezes é difícil de descobrir. Idéia: pensar o que é mais provável mudar. • “Bom design recebe bem as mudanças” - José Ricardo ◦ Isto vale para o código dos testes também, mas os tipos de coisas que causam mudanças são diferentes. ◦ Geralmente, código de teste é melhor bem direto (mínima indireção, sem muita herança e/ou OO)
  20. FIM Thanks! Algumas referências: • http://blog.solidcraft. eu/2012/09/test-driven-traps- part-1.html • http://martinfowler.

    com/articles/mocksArentStubs. html • https://www.destroyallsoftware. com/screencasts/catalog • https://www.facebook. com/notes/kent-beck/when-tdd- doesnt- matter/797644973601702 • Livro do Michael Feathers Elias Dorneles @eliasdorneles