Slide 1

Slide 1 text

Testando código em Python Elias Dorneles @eliasdorneles

Slide 2

Slide 2 text

Ouvi falar de TDD pela 1a vez em 2009

Slide 3

Slide 3 text

Mas levei anos para ver vantagem.

Slide 4

Slide 4 text

YMMV Sua experiência pode ser diferente!

Slide 5

Slide 5 text

Com dez anos de experiência, a gente ainda é adolescente =)

Slide 6

Slide 6 text

Complexidade pode te deixar de coração partido

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

TDD is cool. Porém, é mais comum me encontrar escrevendo testes para código legado.

Slide 9

Slide 9 text

Bugs tendem a reaparecer... Ói nóis qui traveiz...

Slide 10

Slide 10 text

Regra de ouro: quando encontrar bug, adicione um caso para pegá-lo.

Slide 11

Slide 11 text

Cheap trick $ ./meu_script.py out.txt $ diff <(./meu_script.py

Slide 12

Slide 12 text

Cheap trick $ ./meu_script.py out.txt $ diff <(./meu_script.py

Slide 13

Slide 13 text

Para cobrir mais casos, basta usar outros arquivos.

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

Having a test suite is sweet!

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

“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)

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

Verificar a coisa errada atrapalha mais do que ajuda

Slide 25

Slide 25 text

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)

Slide 26

Slide 26 text

Para ter certeza que está checando a coisa certa, faça o teste falhar

Slide 27

Slide 27 text

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!

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

Agora, sim! def test_device_should_be_connected(self): # when: report = get_status_report(self.device) # then: self.assertRegexpMatches(report, r'\bconnected')

Slide 30

Slide 30 text

Dublês de teste (test doubles) Para quando você quiser poupar o oficial

Slide 31

Slide 31 text

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)

Slide 32

Slide 32 text

Biblioteca mock: use para stubs ou para mocks

Slide 33

Slide 33 text

(demo rápida da classe mock.Mock)

Slide 34

Slide 34 text

Python context managers rock!

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

Context managers ajudam com captura/cleanup # USANDO: with script_args(['--opcao1', '--opcao2']): print(sys.argv) # vai mostrar: # ['fake_script.py', '--opcao1', '--opcao2']

Slide 37

Slide 37 text

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)

Slide 38

Slide 38 text

Ú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)

Slide 39

Slide 39 text

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