SlideShare a Scribd company logo
1 of 28
Download to read offline
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
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
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
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
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
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
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?
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
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))
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
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”.
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
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
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
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))..
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
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
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
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
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
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
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
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
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
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
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?
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 ==))
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

More Related Content

More from Danilo J. S. Bellini

(2017-07-22) [TDC] Audiolazy em 2017!
(2017-07-22) [TDC] Audiolazy em 2017!(2017-07-22) [TDC] Audiolazy em 2017!
(2017-07-22) [TDC] Audiolazy em 2017!Danilo J. S. Bellini
 
(2017-05-27) [Grupy-SP] Polígonos, pontos e outras geometrias no Shapely (GIS)
(2017-05-27) [Grupy-SP] Polígonos, pontos e outras geometrias no Shapely (GIS)(2017-05-27) [Grupy-SP] Polígonos, pontos e outras geometrias no Shapely (GIS)
(2017-05-27) [Grupy-SP] Polígonos, pontos e outras geometrias no Shapely (GIS)Danilo J. S. Bellini
 
(2014-08-09) [TDC] AudioLazy 0.6 will robotize you!
(2014-08-09) [TDC] AudioLazy 0.6 will robotize you!(2014-08-09) [TDC] AudioLazy 0.6 will robotize you!
(2014-08-09) [TDC] AudioLazy 0.6 will robotize you!Danilo J. S. Bellini
 
(2014-05-24) [Taubaté Perl Mongers] AudioLazy Python DSP (Digital Signal Proc...
(2014-05-24) [Taubaté Perl Mongers] AudioLazy Python DSP (Digital Signal Proc...(2014-05-24) [Taubaté Perl Mongers] AudioLazy Python DSP (Digital Signal Proc...
(2014-05-24) [Taubaté Perl Mongers] AudioLazy Python DSP (Digital Signal Proc...Danilo J. S. Bellini
 
(2013-11-29) [RuPy] AudioLazy Python DSP (Digital Signal Processing)
(2013-11-29) [RuPy] AudioLazy Python DSP (Digital Signal Processing)(2013-11-29) [RuPy] AudioLazy Python DSP (Digital Signal Processing)
(2013-11-29) [RuPy] AudioLazy Python DSP (Digital Signal Processing)Danilo J. S. Bellini
 
(2013-10-16) [LatinoWare] Processamento de sinais em Python
(2013-10-16) [LatinoWare] Processamento de sinais em Python(2013-10-16) [LatinoWare] Processamento de sinais em Python
(2013-10-16) [LatinoWare] Processamento de sinais em PythonDanilo J. S. Bellini
 
(2013-10-03) [PythonBrasil] AudioLazy, processamento de sinais para música, j...
(2013-10-03) [PythonBrasil] AudioLazy, processamento de sinais para música, j...(2013-10-03) [PythonBrasil] AudioLazy, processamento de sinais para música, j...
(2013-10-03) [PythonBrasil] AudioLazy, processamento de sinais para música, j...Danilo J. S. Bellini
 
(2013-09-30) [PythonBrasil] Síntese em tempo real com a AudioLazy
(2013-09-30) [PythonBrasil] Síntese em tempo real com a AudioLazy(2013-09-30) [PythonBrasil] Síntese em tempo real com a AudioLazy
(2013-09-30) [PythonBrasil] Síntese em tempo real com a AudioLazyDanilo J. S. Bellini
 
(2013-10-17) [LatinoWare] Automatizando o GIMP com Python
(2013-10-17) [LatinoWare] Automatizando o GIMP com Python(2013-10-17) [LatinoWare] Automatizando o GIMP com Python
(2013-10-17) [LatinoWare] Automatizando o GIMP com PythonDanilo J. S. Bellini
 
(2013-10-02) [PythonBrasil] Compatibilidade entre Python 2 e 3
(2013-10-02) [PythonBrasil] Compatibilidade entre Python 2 e 3(2013-10-02) [PythonBrasil] Compatibilidade entre Python 2 e 3
(2013-10-02) [PythonBrasil] Compatibilidade entre Python 2 e 3Danilo J. S. Bellini
 
(2013-07-05) [fisl] Semáforo Gráfico dose para TDD em dojos
(2013-07-05) [fisl] Semáforo Gráfico dose para TDD em dojos(2013-07-05) [fisl] Semáforo Gráfico dose para TDD em dojos
(2013-07-05) [fisl] Semáforo Gráfico dose para TDD em dojosDanilo J. S. Bellini
 
(2013-07-05) [fisl] Compatibilidade entre Python 2 e 3
(2013-07-05) [fisl] Compatibilidade entre Python 2 e 3(2013-07-05) [fisl] Compatibilidade entre Python 2 e 3
(2013-07-05) [fisl] Compatibilidade entre Python 2 e 3Danilo J. S. Bellini
 
(2013-05-20) [DevInSampa] AudioLazy - DSP expressivo e em tempo real para o P...
(2013-05-20) [DevInSampa] AudioLazy - DSP expressivo e em tempo real para o P...(2013-05-20) [DevInSampa] AudioLazy - DSP expressivo e em tempo real para o P...
(2013-05-20) [DevInSampa] AudioLazy - DSP expressivo e em tempo real para o P...Danilo J. S. Bellini
 

More from Danilo J. S. Bellini (17)

(2017-07-22) [TDC] Audiolazy em 2017!
(2017-07-22) [TDC] Audiolazy em 2017!(2017-07-22) [TDC] Audiolazy em 2017!
(2017-07-22) [TDC] Audiolazy em 2017!
 
(2017-05-27) [Grupy-SP] Polígonos, pontos e outras geometrias no Shapely (GIS)
(2017-05-27) [Grupy-SP] Polígonos, pontos e outras geometrias no Shapely (GIS)(2017-05-27) [Grupy-SP] Polígonos, pontos e outras geometrias no Shapely (GIS)
(2017-05-27) [Grupy-SP] Polígonos, pontos e outras geometrias no Shapely (GIS)
 
(2014-08-09) [TDC] AudioLazy 0.6 will robotize you!
(2014-08-09) [TDC] AudioLazy 0.6 will robotize you!(2014-08-09) [TDC] AudioLazy 0.6 will robotize you!
(2014-08-09) [TDC] AudioLazy 0.6 will robotize you!
 
(2014-05-24) [Taubaté Perl Mongers] AudioLazy Python DSP (Digital Signal Proc...
(2014-05-24) [Taubaté Perl Mongers] AudioLazy Python DSP (Digital Signal Proc...(2014-05-24) [Taubaté Perl Mongers] AudioLazy Python DSP (Digital Signal Proc...
(2014-05-24) [Taubaté Perl Mongers] AudioLazy Python DSP (Digital Signal Proc...
 
(2014-04-16) [Garoa HC] Strategy
(2014-04-16) [Garoa HC] Strategy(2014-04-16) [Garoa HC] Strategy
(2014-04-16) [Garoa HC] Strategy
 
(2013-12-18) [Garoa HC] AudioLazy
(2013-12-18) [Garoa HC] AudioLazy(2013-12-18) [Garoa HC] AudioLazy
(2013-12-18) [Garoa HC] AudioLazy
 
(2014-03-26) [7masters] AudioLazy
(2014-03-26) [7masters] AudioLazy(2014-03-26) [7masters] AudioLazy
(2014-03-26) [7masters] AudioLazy
 
(2013-11-29) [RuPy] AudioLazy Python DSP (Digital Signal Processing)
(2013-11-29) [RuPy] AudioLazy Python DSP (Digital Signal Processing)(2013-11-29) [RuPy] AudioLazy Python DSP (Digital Signal Processing)
(2013-11-29) [RuPy] AudioLazy Python DSP (Digital Signal Processing)
 
(2013-10-16) [LatinoWare] Processamento de sinais em Python
(2013-10-16) [LatinoWare] Processamento de sinais em Python(2013-10-16) [LatinoWare] Processamento de sinais em Python
(2013-10-16) [LatinoWare] Processamento de sinais em Python
 
(2013-10-03) [PythonBrasil] AudioLazy, processamento de sinais para música, j...
(2013-10-03) [PythonBrasil] AudioLazy, processamento de sinais para música, j...(2013-10-03) [PythonBrasil] AudioLazy, processamento de sinais para música, j...
(2013-10-03) [PythonBrasil] AudioLazy, processamento de sinais para música, j...
 
(2013-09-30) [PythonBrasil] Síntese em tempo real com a AudioLazy
(2013-09-30) [PythonBrasil] Síntese em tempo real com a AudioLazy(2013-09-30) [PythonBrasil] Síntese em tempo real com a AudioLazy
(2013-09-30) [PythonBrasil] Síntese em tempo real com a AudioLazy
 
(2013-10-17) [LatinoWare] Automatizando o GIMP com Python
(2013-10-17) [LatinoWare] Automatizando o GIMP com Python(2013-10-17) [LatinoWare] Automatizando o GIMP com Python
(2013-10-17) [LatinoWare] Automatizando o GIMP com Python
 
(2013-10-02) [PythonBrasil] Compatibilidade entre Python 2 e 3
(2013-10-02) [PythonBrasil] Compatibilidade entre Python 2 e 3(2013-10-02) [PythonBrasil] Compatibilidade entre Python 2 e 3
(2013-10-02) [PythonBrasil] Compatibilidade entre Python 2 e 3
 
(2013-07-05) [fisl] Semáforo Gráfico dose para TDD em dojos
(2013-07-05) [fisl] Semáforo Gráfico dose para TDD em dojos(2013-07-05) [fisl] Semáforo Gráfico dose para TDD em dojos
(2013-07-05) [fisl] Semáforo Gráfico dose para TDD em dojos
 
(2013-07-05) [fisl] Compatibilidade entre Python 2 e 3
(2013-07-05) [fisl] Compatibilidade entre Python 2 e 3(2013-07-05) [fisl] Compatibilidade entre Python 2 e 3
(2013-07-05) [fisl] Compatibilidade entre Python 2 e 3
 
(2013-05-20) [DevInSampa] AudioLazy - DSP expressivo e em tempo real para o P...
(2013-05-20) [DevInSampa] AudioLazy - DSP expressivo e em tempo real para o P...(2013-05-20) [DevInSampa] AudioLazy - DSP expressivo e em tempo real para o P...
(2013-05-20) [DevInSampa] AudioLazy - DSP expressivo e em tempo real para o P...
 
(2013-05-03) AudioLazy - Slides
(2013-05-03) AudioLazy - Slides(2013-05-03) AudioLazy - Slides
(2013-05-03) AudioLazy - Slides
 

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

  • 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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