(2014-11-05) [PythonBrasil] Testando com py.test e tox

444 visualizações

Publicada em

Minicurso/tutorial sobre o py.test e o tox apresentado no Hotel Armação, Porto de Galinhas - Pernambuco, no dia 2014-11-05, durante a PythonBrasil[10].

Descrição do tutorial:

## Tipo
Tutorial

## Trilha
Tools & methodology

## Nível da audiência
Intermediário

## Idioma
Português

## Título
Testando com py.test e tox

## Descrição
Tutorial para o aprendizado sobre o uso prático do pacote py.test para realização de testes de diversos tipos. Tópicos:

- Comportamento básico para coleta e execução de testes;
- Testando exceções;
- Testes parametrizados e seus usos com oráculos, testes aleatórios;
- Cobertura de código com pytest-cov;
- Testando apenas uma parte de uma suíte;
- Integrando com doctests;
- Criando fixtures personalizadas;
- Mock/stub/fake/dummy com a fixture monkeypatch;
- Testando warnings;
- Usando tox para automatizar testes em múltiplos ambientes (e.g. Python 2 e 3);
- Configurações (avançadas) para tempo de coleta e tempo de setup;
- Usando skip, xfail e deseleção para testes que irão falhar;
- Testes envolvendo arquivos temporários;

O tutorial inclui uma breve discussão sobre o que pode ser testado, além de exemplos sobre comparação de ponto flutuante, aproximações e manutenção de resultados para testes que envolvam cálculo numérico ou dados científicos/multimídia.

É necessário levar o computador com o Python instalado (2.7 ou 3.4, preferencialmente ambos), e com o pip (ou algo equivalente) disponível para instalação de pacotes. Pode-se instalar previamente os pacotes pytest, pytest-cov e tox.

O tutorial é voltado para quem já sabe programar em Python. Embora não seja fundamental, é de grande ajuda ter o conhecimento prévio sobre assuntos como gerenciadores de contexto, exceções, decorators, orientação a objetos e arquivos setup.py.

A meta deste tutorial é a utilização/realização prática de testes, sem enfatizar tópicos de "engenharia de software" referentes à importância/relevância da utilização de testes, ou mesmo quanto às suas classificações.

Publicada em: Tecnologia
0 comentários
0 gostaram
Estatísticas
Notas
  • Seja o primeiro a comentar

  • Seja a primeira pessoa a gostar disto

Sem downloads
Visualizações
Visualizações totais
444
No SlideShare
0
A partir de incorporações
0
Número de incorporações
7
Ações
Compartilhamentos
0
Downloads
4
Comentários
0
Gostaram
0
Incorporações 0
Nenhuma incorporação

Nenhuma nota no slide

(2014-11-05) [PythonBrasil] Testando com py.test e tox

  1. 1. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE TTeessttaannddoo ccoomm ppyy..tteesstt ee ttooxx Danilo de Jesus da Silva Bellini Twitter: @danilobellini http://pytest.org/ https://tox.readthedocs.org/ https://github.com/schlamar/pytest-cov http://nedbatchelder.com/code/coverage
  2. 2. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE AAssppeeccttooss ggeerraaiiss ● BBrreevvee hhiissttóórriiaa – OOrriiggiinnaallmmeennttee,, ppaarrttee ddoo ““ppyy”” – HHoollggeerr KKrreekkeell ((ccrriiaaddoorr)) ● OObbjjeettiivvoo cceennttrraall – AAuuttoommaattiizzaarr ((ee ppaaddrroonniizzaarr)) tteesstteess ● TTeessttaannddoo...... – CCPPyytthhoonn 22..xx ((22..66++)) ee 33..xx – PPyyPPyy – CCóóddiiggooss eemm oouuttrraass lliinngguuaaggeennss
  3. 3. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE AAmmbbiieennttee vviirrttuuaall ((ooppcciioonnaall)) ee iinnssttaallaaççããoo ● AAddmmiittiinnddoo oo vviirrttuuaalleennvv iinnssttaallaaddoo ee aattuuaalliizzaaddoo ((aalléémm ddoo ppiipp)),, ccrriiee uumm ddiirreettóórriioo ““ppyyttuutt”” ccoomm oo ccoommaannddoo:: EEssttee sseerráá oo aammbbiieennttee ppaarraa aa rreeaalliizzaaççããoo ddooss tteesstteess,, aalléémm ddaa iinnssttaallaaççããoo ddoo ppyy..tteesstt ee ddoo ttooxx.. ● AAttiivvee oo aammbbiieennttee ((aass lliinnhhaass ggaannhhaarrããoo uumm pprreeffiixxoo)):: ● IInnssttaallee oo ppyy..tteesstt,, oo ppyytteesstt--ccoovv ee oo ttooxx ((nnããoo--ooppcciioonnaall)):: ● PPaarraa ddeessaattiivvaarr:: $$ vviirrttuuaalleennvv ppyyttuutt $$ .. ~~//ppyyttuutt//bbiinn//aaccttiivvaattee $$ ppiipp iinnssttaallll ttooxx ppyytteesstt ppyytteesstt--ccoovv $$ ddeeaaccttiivvaattee Ou no diretório de instalação caso não tenha criado em $HOME/pytut
  4. 4. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE PPrriimmeeiirrooss ppaassssooss ● AArrqquuiivvoo tteesstt__mmuull..ppyy:: ● RRooddaarr oo tteessttee:: def multiplica(a, b): def multiplica(a, b): def test_multiplica_7_8(): ● OO tteessttee ppaassssaa?? – CCoorrrriijjaa oo ccóóddiiggoo return a + b return a + b def test_multiplica_7_8(): assert multiplica(7, 8) == 56 assert multiplica(7, 8) == 56 $$ ppyy..tteesstt Os números à direita dos slides se referem a uma sugestão ade organização das etapas do tutorial em diferentes diretórios ou commits 01_01 01_02
  5. 5. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE CCoommoo oo ppyy..tteesstt eennccoonnttrraa ooss tteesstteess?? ● CCoonnvveennççããoo ddee nnoommeess!! – PPrreeffiixxooss ““tteesstt__”” nnooss aarrqquuiivvooss ee ffuunnççõõeess//mmééttooddooss – PPrreeffiixxoo TTeesstt nnooss nnoommeess ddaass ccllaasssseess ● TTeennttee oo eexxeemmpplloo aanntteerriioorr nnoovvaammeennttee,, mmaass mmaanntteennddoo oo aarrqquuiivvoo ccoomm oo nnoommee mmuullttiipplliiccaa..ppyy – OO qquuee aaccoonntteeccee?? – EE cchhaammaannddoo ccoomm oo nnoommee ddoo aarrqquuiivvoo ccoommoo ppaarrââmmeettrroo?? $$ ppyy..tteesstt mmuullttiipplliiccaa..ppyy 01_03 Para organização estrutural em diretórios e outras sugestões/convenções, veja http://pytest.org/latest/goodpractises.html
  6. 6. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE FFiibboonnaaccccii ● CCoomm aa ffuunnççããoo ffiibboonnaaccccii eemm uumm aarrqquuiivvoo ffiibb..ppyy ...... def fibonacci(x): def fibonacci(x): return n if n <= 1 else fibonacci(n - 1) + fibonacci(n - 2) return n if n <= 1 else fibonacci(n - 1) + fibonacci(n - 2) …… ffaaççaa rroottiinnaass ddee tteesstteess ((ffuunnççõõeess)) ppaarraa ppeelloo mmeennooss 88 ddiiffeerreenntteess eennttrraaddaass vváálliiddaass eemm uumm aarrqquuiivvoo tteesstt__ffiibb..ppyy from fib import fibonacci from fib import fibonacci # Continuar ... # Continuar ... ● RRooddaarr ccoomm:: $$ ppyy..tteesstt 02_01
  7. 7. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE TTeesstteess ppaarraammeettrriizzaaddooss ● IImmpplleemmeennttee uummaa vveerrssããoo aalltteerrnnaattiivvaa aaoo tteesstt__ffiibb..ppyy uuttiilliizzaannddoo aappeennaass uumm úúnniiccoo tteessttee ccoomm vváárriiooss ““aasssseerrtt”” – OO qquuee aaccoonntteeccee ccoomm aa ccoonnttaaggeemm ddooss tteesstteess?? ● IImmpplleemmeennttee oo tteesstt__ffiibb..ppyy uussaannddoo:: 02_02 02_03 import pytest from fib import fibonacci import pytest from fib import fibonacci schema = "n", "out" table = [ # Pares (entrada "n", saída "out") schema = "n", "out" table = [ # Pares (entrada "n", saída "out") (0, 0), (1, 1), # ... complete com os demais pares (0, 0), (1, 1), # ... complete com os demais pares ] ] @pytest.mark.parametrize(schema, table) def test_mapeia_entrada_saida(n, out): @pytest.mark.parametrize(schema, table) def test_mapeia_entrada_saida(n, out): assert fibonacci(n) == out assert fibonacci(n) == out O que ocorre quando se utiliza o decorator pytest.mark.p arametrize mais de uma vez?
  8. 8. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE UUssaannddoo mmaaiiss ddee uummaa vveezz oo ddeeccoorraattoorr ppyytteesstt..mmaarrkk..ppaarraammeettrriizzee Extra! ● PPrroodduuttoo ccaarrtteessiiaannoo!! ● PPoossssiibbiilliittaa mmaaiiss tteesstteess ddoo qquuee lliinnhhaass ddee ccóóddiiggoo ppaarraa eesstteess ● IInnssiirraa eessttee ““tteessttee”” ppaarraa oo ““pprroojjeettoo”” ddaa mmuullttiipplliiccaaççããoo – NNaa pprrááttiiccaa,, tteesstteess nnããoo ssããoo uummaa mmeerraa rreeppeettiiççããoo ddoo ccóóddiiggoo – ÚÚttiill qquuaannddoo ccoommbbiinnaaddoo ccoomm oorrááccuullooss import pytest import pytest p = pytest.mark.parametrize @p("a", [0, 1, 2, 3]) @p("b", [5, 7, 9, 12]) def test_multiplica_parametrizado(a, b): p = pytest.mark.parametrize @p("a", [0, 1, 2, 3]) @p("b", [5, 7, 9, 12]) def test_multiplica_parametrizado(a, b): assert multiplica(a, b) == a * b assert multiplica(a, b) == a * b 01_04
  9. 9. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE DDiiccaass ● TTaabbeellaass ddee ddaaddooss ddeevveemm sseerr iitteerráávveeiiss,, nnããoo nneecceessssaarriiaammeennttee lliissttaass,, ee..gg.. ttaabbllee == eennuummeerraattee(([[00,, 11,, 11,, 22,, 33,, 55,, 88,, 1133]])) 02_04 ● NNaa pprreesseennççaa ddee mmuuiittaass rroottiinnaass ddee tteesstteess sseennddoo ppaarraammeettrriizzaaddaass,, ppooddee--ssee ffaazzeerr …… pp == ppyytteesstt..mmaarrkk..ppaarraammeettrriizzee …… ppaarraa ddeeffiinniirr oo ddeeccoorraattoorr ““@@pp((......))”” ppaarraa ffoorrnneecceerr ppaarrââmmeettrrooss aaoo tteessttee ppaarraammeettrriizzaaddoo ● SScchheemmaa ddee uumm úúnniiccoo vvaalloorr nnããoo pprreecciissaa sseerr uummaa ttuuppllaa ● AAss mmeessmmaass ttaabbeellaass ppooddeemm sseerr uuttiilliizzaaddaass eemm ddiiffeerreenntteess rroottiinnaass ddee tteesstteess ((ee..gg.. tteessttaannddoo mmúúllttiippllaass iimmpplleemmeennttaaççõõeess ddee uummaa mmeessmmaa ttaarreeffaa,, ppaatttteerrnn ssttrraatteeggyy))
  10. 10. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE EExxcceeççããoo ● MMooddiiffiiqquuee aa ffuunnççããoo ffiibboonnaaccccii ppaarraa llaannççaarr uummaa eexxcceeççããoo VVaalluueeEErrrroorr qquuaannddoo aa eennttrraaddaa ffoorr nneeggaattiivvaa.. if n < 0: if n < 0: raise ValueError("Use apenas inteiros positivos") raise ValueError("Use apenas inteiros positivos") ● MMaass ccoommoo tteessttaarr?? – GGeerreenncciiaaddoorreess ddee ccoonntteexxttoo!! with pytest.raises(ValueError): with pytest.raises(ValueError): # Algo que deveria lançar um ValueError # Algo que deveria lançar um ValueError – CCrriiee ppeelloo mmeennooss ddooiiss tteesstteess ccoonntteennddoo eessssee ggeerreenncciiaaddoorr ddee ccoonntteexxttoo,, uumm nnoo qquuaall aa eexxcceeççããoo ddeevveerriiaa ooccoorrrreerr ((eennttrraaddaa nneeggaattiivvaa)) ee oouuttrroo nnoo qquuaall nnããoo ddeevveerriiaa ooccoorrrreerr eexxcceeççããoo.. ● AAllgguumm tteessttee ffaallhhoouu?? CCoollooqquuee eessttee ddeeccoorraattoorr nneellee:: “xfail” = expected to fail @@ppyytteesstt..mmaarrkk..xxffaaiill 02_05
  11. 11. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE TTeessttaannddoo aa mmeennssaaggeemm ddee eexxcceeççããoo ● OO bbllooccoo wwiitthh aappeennaass tteessttaa ssee aa eexxcceeççããoo ooccoorrrreeuu.. MMaass aa eexxcceeççããoo ppooddeerriiaa tteerr ooccoorrrriiddoo ccoomm uummaa mmeennssaaggeemm ddiiffeerreennttee ddaa ddeesseejjaaddaa ((ee..gg.. mmaaiiss ddee uummaa ffoorrmmaa ppaarraa oo vvaalloorr ddee eennttrraaddaa eessttaarr ffoorraa ddoo ddoommíínniioo ddee aapplliiccaabbiilliiddaaddee ddaa ffuunnççããoo)) ● FFaaççaa uumm tteessttee uussaannddoo aa eennttrraaddaa ““22jj”” ((oo nnúúmmeerroo iimmaaggiinnáárriioo 22)),, aa qquuaall llaannççaa uumm TTyyppeeEErrrroorr.. VVeerriiffiiqquuee ssee aa mmeennssaaggeemm ccoonnttéémm aa ppaallaavvrraa ““ccoommpplleexx””.. 02_07 with pytest.raises(TypeError): with pytest.raises(TypeError): try: # Bloco que deveria lançar a exceção except TypeError as exc: assert "complex" in str(exc) raise # Propaga o TypeError try: # Bloco que deveria lançar a exceção except TypeError as exc: assert "complex" in str(exc) raise # Propaga o TypeError 02_06 …… ee uussaannddoo oo ppyy..ccooddee..EExxcceeppttiioonnIInnffoo(()) ...... with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo: # Bloco que deveria lançar a exceção # Bloco que deveria lançar a exceção assert "complex" in str(excinfo.value) assert "complex" in str(excinfo.value) Dica: Troque o nome “complex” por outro que não existe na string, a fim de “testar o teste”.
  12. 12. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE OOrrááccuullooss ● IImmpplleemmeennttaaççããoo ddee rreeffeerrêênncciiaa pprroonnttaa ppaarraa ppeelloo mmeennooss ppaarrttee ddoo ddoommíínniioo.. ● UUttiilliizzaarr uummaa iimmpplleemmeennttaaççããoo ((ccoommpplleettaa oouu ppaarrcciiaall)) ppaarraa tteessttaarr oouuttrraa – PPoossssiibbiilliiddaaddee ddee ccrriiaaççããoo mmaassssiivvaa ddee tteesstteess.. ● TTeessttee eessttaa iimmpplleemmeennttaaççããoo aalltteerrnnaattiivvaa ppaarraa 3300 eennttrraaddaass ddiiffeerreenntteess ((ppeeqquueennaass)) – SSeemm oorrááccuullooss,, tteesstteess aalleeaattóórriiooss rreepprreesseennttaamm aa rreessiissttêênncciiaa ddoo ccóóddiiggoo aa ““ffaallhhaa ddee sseeggmmeennttaaççããoo”” ee ccooiissaass ssiimmiillaarreess ((nnããoo ffaarreemmooss nneessttee mmiinniiccuurrssoo//ttuuttoorriiaall)).. – AAss eennttrraaddaass ppaarraa uussoo ccoomm uumm oorrááccuulloo,, ddeennttrroo ddooss ddoommíínniiooss rreelleevvaanntteess,, ppooddeemm sseerr ggeerraaddaass aalleeaattoorriiaammeennttee.. – RReepprroodduuttiibbiilliiddaaddee 02_08 phi = .5 + .5 * 5 ** .5 # Golden ratio! def fibonacci_closed_form(n): phi = .5 + .5 * 5 ** .5 # Golden ratio! def fibonacci_closed_form(n): ● TTeesstteess aalleeaattóórriiooss return int(round(phi ** n * 5 ** -.5)) return int(round(phi ** n * 5 ** -.5)) ● NNeecceessssáárriioo?? ● SSeeeedd ffiixxoo oouu hhaarrdd--ccooddeedd?? Dica: Use nomes para os testes que permita a seleção com: $ pytest -k parte_do_nome Dica: Usar o decorator @audiolazy.cached (Python 2/3) ou o @functools.lru_cache (apenas Python 3) na “fibonacci” original resolve o problema de desempenho
  13. 13. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE AAppeennaass ccoolleettaarr tteesstteess ● QQuueerreemmooss ggaarraannttiirr qquuee oo oorrááccuulloo tteessttaaddoo ccoomm vvaalloorreess aalleeaattóórriiooss tteennhhaa sseemmpprree oo mmeessmmoo sseeeedd.. MMaass aanntteess,, ffaaççaammooss ooss tteesstteess aalleeaattóórriiooss:: from random import sample @p("n", sample(range(32), 16)) def test_oraculo_entrada_aleatoria(n): from random import sample @p("n", sample(range(32), 16)) def test_oraculo_entrada_aleatoria(n): assert fibonacci_closed_form(n) == fibonacci(n) assert fibonacci_closed_form(n) == fibonacci(n) ● VVeejjaa ooss vvaalloorreess ddee ““nn”” aa ccaaddaa cchhaammaaddaa ccoomm:: $$ ppyy..tteesstt ----ccoolllleecctt--oonnllyy 02_09
  14. 14. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE EExxeemmpplloo ddee ccoonnfftteesstt..ppyy:: FFiixxaannddoo oo sseeeedd ● VVaammooss ffoorrççaarr ppaarraa qquuee ooss vvaalloorreess ddee ““nn”” uuttiilliizzaaddooss nnooss tteesstteess ““aalleeaattóórriiooss”” ccoomm oorrááccuulloo sseejjaamm sseemmpprree ooss mmeessmmooss.. ● CCrriiee uumm aarrqquuiivvoo ccoonnfftteesstt..ppyy nnoo mmeessmmoo ddiirreettóórriioo eemm qquuee oo ppyy..tteesstt éé cchhaammaaddoo ccoonntteennddoo ● ppyytteesstt__ccoonnffiigguurree import random def pytest_configure(config): import random def pytest_configure(config): random.seed(42) 02_10 random.seed(42) – ““HHooookk”” cchhaammaaddoo aanntteess ddaa ccoolleettaa ddooss tteesstteess – HHáá oouuttrrooss ““hhooookkss”” iinniicciiaaddooss ccoomm ““ppyytteesstt__”” ppaarraa ccaaddaa eettaappaa ddoo pprroocceessssoo ddee tteesstteess
  15. 15. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE Personalização ddaass eettaappaass ddoo pprroocceessssoo ddoo ppyy..tteesstt (““hhooookkss””)) http://pytest.org/latest/plugins.html ● ÉÉ ppoossssíívveell iinnsseerriirr uumm pprroocceessssoo ppaarraa aanntteess ddee ccaaddaa tteessttee,, aappóóss ccaaddaa tteessttee,, aanntteess ddaa ccoolleettaa,, aappóóss aa ccoolleettaa (ee..gg.. rreeoorrddeennaarr ooss tteesstteess)),, eettcc.. eemm uumm aarrqquuiivvoo ““ccoonnfftteesstt..ppyy”” ccoomm ffuunnççõõeess iinniicciiaaddaass eemm ““ppyytteesstt__”” – NNoorrmmaallmmeennttee uussaaddoo eemm ccaassooss eessppeeccííffiiccooss,, ee..gg.. ccoomm wwaarrnniinnggss ppaarraa rreemmoovveerr aass aalltteerraaççõõeess rreeaalliizzaaddaass nnoo pprróópprriioo gglloobbaallss ddaa ffuunnççããoo//mmééttooddoo qquuee rreeaalliizzoouu oo wwaarrnniinngg ● https://docs.python.org/2/library/warnings.html ● WWaarrnniinnggss ssããoo ddiiffíícceeiiss ddee tteessttaarr,, ttaannttoo ccoomm oo ffiixxttuurree ppaaddrrããoo ““rreeccwwaarrnn”” ddoo ppyy..tteesstt ccoommoo uussaannddoo ddiirreettaammeennttee oo mmóódduulloo ““wwaarrnniinnggss”” ppaaddrrããoo ddoo PPyytthhoonn.. ● PPaarraa tteessttaarr aallggoo nneessssaass ccoonnddiiççõõeess,, éé rreeccoommeennddáávveell qquuee ssee pprrooccuurree ppoorr eexxeemmppllooss aanntteess (ee..gg.. AAuuddiiooLLaazzyy))..
  16. 16. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE DDoocctteessttss (tteesstteess ddee ddooccuummeennttaaççããoo)) ● CCoommppaarraa tteexxttoo ● IImmpplleemmeennttee aa ffuunnççããoo aaoo llaaddoo eemm uumm aarrqquuiivvoo nnoottaa..ppyy ● CChhaammee oo ppyy..tteesstt ccoomm:: ● CCoollooqquuee uumm tteessttee ddee ddooccuummeennttaaççããoo ccoomm uummaa ssttrriinngg ccoommoo eennttrraaddaa def nome_nota(pitch): def nome_nota(pitch): """ """ Nome Nome da da nota nota dado dado o o pitch pitch MIDI MIDI ((em em semitons) semitons) caso caso esteja esteja na na pentatônica pentatônica de de Cm. Cm. >>> >>> nome_nome_nota(nota(70) 70) # # Bb4 Bb4 ''Bb' Bb' >>> nome_nota(69) # A4 (La central) Traceback (most recent call last): >>> nome_nota(69) # A4 (La central) Traceback (most recent call last): ... ... ValueError: Fora da escala! """ if pitch % 12 == 0: ValueError: Fora da escala! """ if pitch % 12 == 0: return "C" return "C" if pitch % 12 == 3: if pitch % 12 == 3: return "Eb" return "Eb" if pitch % 12 == 5: if pitch % 12 == 5: return "F" return "F" if pitch % 12 == 7: if pitch % 12 == 7: return "G" return "G" if pitch % 12 == 10: if pitch % 12 == 10: return "Bb" return "Bb" raise raise ValueError("ValueError("Fora Fora da da escala!") escala!") 03_01 $$ ppyy..tteesstt ----ddoocctteesstt--mmoodduulleess … (Ellipsis): Parte do doctest para “casar com o que vier” 03_02
  17. 17. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE CCoobbeerrttuurraa ddee ccóóddiiggoo ● CCrriiee uumm ttooxx..iinnii ccoonntteennddoo [pytest] addopts = --doctest-modules [pytest] addopts = --doctest-modules Tente também com html no lugar de term-missing --cov-config tox.ini --cov-report term-missing --cov nota --cov-config tox.ini --cov-report term-missing --cov nota AAssssiimm nnããoo éé mmaaiiss nneecceessssáárriioo ddiiggiittaarr ppaarrââmmeettrrooss aaoo cchhaammaarr oo ppyy..tteesstt (eexxcceettoo ppaarrââmmeettrrooss ccoommpplleemmeennttaarreess,, ee..gg.. ““--kk””)) ● ----ccoovv--ccoonnffiigg ttooxx..iinnii – UUssaa oo ttooxx..iinnii ccoommoo aarrqquuiivvoo ddee ccoonnffiigguurraaççããoo ddoo ttooxx,, ppyy..tteesstt ee ppyytteesstt--ccoovv.. – AAvvaalliiee aa ccoobbeerrttuurraa ddee ccóóddiiggoo ccoomm bbrraanncchhiinngg ccoollooccaannddoo iissttoo ttaammbbéémm nnoo ttooxx..iinnii (ccoonnffiigguurraa oo ppyytteesstt--ccoovv)):: ● ----ccoovv nnoottaa [run] branch = True [run] branch = True – EEssppeecciiffiiccaa oo ppaaccoottee//mmóódduulloo qquuee ddeevvee sseerr aavvaalliiaaddoo (nnoottaa..ppyy)) ● CCoommpplleettaarr ddoocctteessttss ppaarraa cchheeggaarr aa 110000%% ddee ccoobbeerrttuurraa.. 03_03
  18. 18. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE TTooxx ● Geerreenncciiaa mmúúllttiippllooss aammbbiieenntteess vviirrttuuaaiiss,, ppaarraa aauuttoommaattiizzaarr ooss tteesstteess eemm ttooddooss ooss aammbbiieenntteess ● EExxiiggêênncciiaass:: – UUmm aarrqquuiivvoo sseettuupp..ppyy ddoo pprroojjeettoo (iinnssttaallaaççããoo//ccoonnffiigguurraaççããoo ddoo ““ppaacckkaaggee””)) – UUmm aarrqquuiivvoo ttooxx..iinnii (ccoonnffiigguurraaççããoo ddoo ttooxx ee ppyy..tteesstt)) ● VVaammooss ffaazzeerr nnooss 22 pprriimmeeiirrooss ddooss 33 ““pprroojjeettooss”” ccrriiaaddooss,, ppaarraa tteessttaarr ttaannttoo nnoo PPyytthhoonn 22 ccoommoo nnoo PPyytthhoonn 33.. from from setuptools setuptools import import setup setup setup(setup(name="name="pytut") pytut") EEssttee setup.py é MÍNIMO. O nome é usado pelo tox para criar um egg [tox] envlist = py27, py34 [tox] envlist = py27, py34 [testenv] deps = pytest commands = py.test [testenv] deps = pytest commands = py.test Exemplo de parte do tox.ini que configura o tox. 01_05 02_11 $$ ttooxx
  19. 19. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE TTooxx ++ ppyy..tteesstt ++ ddoocctteessttss Extra! ● PPaarraa tteessttaarr ddoocctteessttss,, oo ppyy..tteesstt aavvaalliiaa ttooddooss ooss ““**..ppyy”” nnããoo aappeennaass ooss aarrqquuiivvooss iinniicciiaaddooss ccoomm ““tteesstt__”” – NNeecceessssáárriioo aavviissaarr oo ttooxx ppaarraa iinnssttaallaarr oo ppyytteesstt--ccoovv [testenv] deps = pytest [testenv] deps = pytest pytest-cov pytest-cov Altera o comando de instalação das dependências install_command = pip install {opts} {packages} install_command = pip install {opts} {packages} – IImmppoorrttaarr oo sseettuupp..ppyy ggeerraa ccoonnfflliittoo ● SSoolluuççõõeess ppoossssíívveeiiss (bbaassttaa uuttiilliizzaarr uummaa)):: from setuptools import setup if __name__ == "__main__": setup(name="pytut") EEvviittaarr que o “setup” Avisar no tox.ini para o ppyy..tteesstt iiggnnoorraarr oo sseettuupp..ppyy [pytest] addopts = ... --ignore setup.py ● CCoollooqquuee oo ttooxx ccoomm oo tteerrcceeiirroo ““pprroojjeettoo”” ccrriiaaddoo nneessttee ttuuttoorriiaall 03_04 from setuptools import setup if __name__ == "__main__": setup(name="pytut") seja chamado ao importar o setup.py [pytest] addopts = ... --ignore setup.py
  20. 20. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE FFiixxttuurreess ● JJáá uussaammooss ffiixxttuurreess!! – ppyytteesstt..mmaarrkk..ppaarraammeettrriizzee ● SSããoo uuttiilliizzaaddaass ccoommoo PPAARRÂÂMMEETTRROOSS nnaass rroottiinnaass ddee tteessttee.. PPooddeemmooss,, ppoorr eexxeemmpplloo,, ccrriiaarr uummaa rroottiinnaa ppaarraa aacceessssaarr uumm rreeccuurrssoo qquuee pprreecciissaa sseerr lliibbeerraaddoo aaoo ffiinnaall ddee sseeuu uussoo oouu ppoossssuuii uumm ““mmoocckk”” (bbaannccoo ddee ddaaddooss,, iinnssttââcciiaa WWSSGII,, eettcc..)).. ● TTeessttaarreemmooss aallggoo qquuee aacceessssaa ddaaddooss aarrmmaazzeennaaddooss eemm uumm aarrqquuiivvoo.. CCoommeeççaammooss aavvaalliiaannddoo ssee uumm aarrqquuiivvoo ““ddaaddooss..ttxxtt”” eexxiissttee ee eessttáá vvaazziioo:: # Sem fixture (por enquanto) def test_arquivo_vazio(): # Sem fixture (por enquanto) def test_arquivo_vazio(): with open("dados.txt") as arq: with open("dados.txt") as arq: assert not arq.read(1) assert not arq.read(1) 04_01 test_arquivo.py
  21. 21. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE YYiieelldd ffiixxttuurree (ffiixxttuurreess ppeerrssoonnaalliizzaaddaass)) @pytest.yield_fixture def nome_fixture(): # setup yield valor # teardown Modelo ● DDeeffiinniiddaa aaoo eessttiilloo ddee ggeerreenncciiaaddoorr ddee ccoonntteexxttoo...... @pytest.yield_fixture def arq(): @pytest.yield_fixture def arq(): with open("dados.txt") as f: with open("dados.txt") as f: yield f yield f ......ee nnooss tteesstteess,, aappaarreeccee ccoommoo ppaarrââmmeettrroo:: 04_02 # Sem fixture (por enquanto) def test_arquivo_vazio(arq): assert not arq.read(1) ● PPooddee--ssee uussaarr aa mmeessmmaa ffiixxttuurree eemm mmaaiiss ddee uumm tteessttee.. FFaaççaamm iissssoo eemm uumm nnoovvoo tteessttee qquuee vveerriiffiiccaa ssee oo aarrqquuiivvoo nnããoo eessttáá vvaazziioo (ccoomm xxffaaiill)).. 04_03 # Sem fixture (por enquanto) def test_arquivo_vazio(arq): assert not arq.read(1) @pytest.yield_fixture def nome_fixture(): # setup yield valor # teardown
  22. 22. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE EEssccooppoo ● ÉÉ ppoossssíívveell ffaazzeerr ooss ddooiiss tteesstteess ((tteessttaarr ssee vvaazziioo ee tteessttaarr ssee nnããoo vvaazziioo)) ppaassssaarreemm aaoo mmeessmmoo tteemmppoo?? ......ee ssee oo aarrqquuiivvoo mmuuddaarr eennttrree ooss tteesstteess?? @pytest.yield_fixture def arq(): @pytest.yield_fixture def arq(): with open("dados.txt", "r+") as f: with open("dados.txt", "r+") as f: backup = f.read() yield f backup = f.read() yield f with open("dados.txt", "w") as f: with open("dados.txt", "w") as f: f.write(backup) f.write(backup) def test_arquivo_vazio(arq): def test_arquivo_vazio(arq): arq.seek(0) assert not arq.read(1) arq.write("A-ha!") arq.seek(0) assert not arq.read(1) arq.write("A-ha!") def test_arquivo_nao_vazio(arq): def test_arquivo_nao_vazio(arq): arq.seek(0) assert arq.read(1) arq.seek(0) assert arq.read(1) EVITAR! Normalmente testes são INdependentes entre si @@ppyytteesstt..yyiieelldd__ffiixxttuurree((ssccooppee==""sseessssiioonn"")) 04_04 FFuunncciioonnaa?? EE ssee aa ffiixxttuurree oobbttiivveerr ““ff”” ssoommeennttee uummaa vveezz nnaa sseessssããoo?? 04_05 O uso de escopo permite otimizar testes evitando a necessidade de setup/teardown para cada teste
  23. 23. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE OOuuttrrooss rreeccuurrssooss ddoo ppyy..tteesstt:: AArrqquuiivvooss tteemmppoorráárriiooss ● HHáá ddiivveerrssaass ffoorrmmaass uussaannddoo aa ssttaannddaarrdd lliibbrraarryy from tempfile import NamedTemporaryFile import pytest @pytest.yield_fixture def tmp(): from tempfile import NamedTemporaryFile import pytest @pytest.yield_fixture def tmp(): with NamedTemporaryFile() as f: with NamedTemporaryFile() as f: yield f # f.name possui o nome do arquivo yield f # f.name possui o nome do arquivo ● OOuu uussaannddoo oo pplluuggiinn ““ttmmppddiirr”” ddoo ppyy..tteesstt – http://pytest.org/latest/tmpdir.html
  24. 24. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE SSkkiipp//xxffaaiill ● HHáá tteesstteess qquuee ppooddeemm ffaazzeerr sseennttiiddoo eemm ssoommeennttee uumm ddooss aammbbiieenntteess ((ee..gg.. tteesstteess qquuee ddeeppeennddeemm ddoo iitteerrttoooollss..aaccccuummuullaattee oouu ddoo ffuunnccttoooollss..llrruu__ccaacchhee qquuee eexxiisstteemm aappeennaass nnoo PPyytthhoonn 33)).. ● DDeeccoorraattoorrss ((““mmaarrkk””)),, [[ppoossssiivveellmmeennttee]] ccoomm ccoonnddiiççõõeess ppaarraa rreeaalliizzaaççããoo ddoo((ss)) tteessttee((ss)) mmaarrccaaddooss – ppyytteesstt..mmaarrkk..sskkiippiiff – ppyytteesstt..mmaarrkk..xxffaaiill ● IImmppeerraattiivvoo ((ccoommaannddooss)) – ppyytteesstt..sskkiipp – ppyytteesstt..xxffaaiill Usamos o mark.xfail incondicional no 02_05
  25. 25. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE MMoocckk//ssttuubb//ffaakkee//dduummmmyy ccoomm aa ffiixxttuurree mmoonnkkeeyyppaattcchh ● FFiixxttuurree mmoonnkkeeyyppaattcchh – MMééttooddoo ““sseettaattttrr”” – MMeessmmaa ssiinnttaaxxee ddoo bbuuiilltt--iinn sseettaattttrr ((ee ____sseettaattttrr____)) – MMoonnkkeeyyppaattcchh..sseettaattttrr(()) ● http://pytest.org/latest/monkeypatch.html
  26. 26. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE PPoonnttoo fflluuttuuaannttee ● CCoommppaarraarr ppoorr aapprrooxxiimmaaççããoo – VVaalloorr aabbssoolluuttoo ddaa ddiiffeerreennççaa – EErrrroo ppeerrcceennttuuaall//rreellaattiivvoo ((nnããoo--ssiimmééttrriiccoo)) – TToolleerrâânncciiaa eemm nnúúmmeerroo ddee bbiittss ddee mmaannttiissssaa ● HHáá iimmpplleemmeennttaaççõõeess pprroonnttaass – nnuummppyy..iisscclloossee,, nnuummppyy..aallllcclloossee – aauuddiioollaazzyy..aallmmoosstt__eeqq – uunniitttteesstt..TTeessttCCaassee..aasssseerrttAAllmmoossttEEqquuaall ● UUssoo ddee aarrrreeddoonnddaammeennttooss eexxppllíícciittooss Extra! É possível usar o oráculo do Fibonacci para verificar os dígitos mais significativos de valores maiores de entrada?
  27. 27. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE MMiisscceellâânneeaa $ py.test --help usage: py.test [options] [file_or_dir] [file_or_dir] [...] ... $ py.test --help usage: py.test [options] [file_or_dir] [file_or_dir] [...] ... ● VVeejjaamm aa aajjuuddaa ddoo ppyy..tteesstt!! – TTooddooss ooss ppaarrââmmeettrrooss ssããoo ooppcciioonnaaiiss,, mmaass qquuaaiiss ssããoo ttooddooss ooss ppaarrââmmeettrrooss?? ● HHáá mmuuiittaa ddooccuummeennttaaççããoo nnaa IInntteerrnneett – Liinnkkss nnaa aapprreesseennttaaççããoo ((pprriimmeeiirroo ee úúllttiimmoo sslliiddeess)) ● OOppeenn ssoouurrccee!! – CCoollaabboorraaççõõeess ==))
  28. 28. Testando com py.test e tox – Danilo J. S. Bellini – @danilobellini 2014-11-05 – Recife / PE Perguntas FFIIMM!! ? OObbrriiggaaddoo!! hhttttpp::////ppyytteesstt..oorrgg// hhttttppss::////ttooxx..rreeaaddtthheeddooccss..oorrgg// hhttttppss::////ggiitthhuubb..ccoomm//sscchhllaammaarr//ppyytteesstt--ccoovv hhttttpp::////nneeddbbaattcchheellddeerr..ccoomm//ccooddee//ccoovveerraaggee

×