Ian Cooper: "TDD, where did it all go wrong"
Kent Beck:
Discussões como "qual a unidade a ser testada" é que geraram coisas como BDD e ATDD (Acceptance Test-Driven Development).
Reddit: Devo escrever testes para a validação interna do Django?
... bom, talvez sim.
Nossos testes End-to-End.
Gary Bernhardt: Fast Test, Slow Test
... soa familiar?
... continua soando familiar?
Qual o valor desse teste para o meu projeto?
Se eu estou escrevendo testes do meu modelo sem que seja integrado com o meu controller, eu estou testando o que?
Aderência a arquitetura do projeto.
Se o teste que verifica a funcionalidade para o usuário (integração) produz mais valor que o teste que garante a aderência do projeto à uma arquitetura, qual teste deve ser rodado primariamente?
"Testes de integração são lentos, então eu tenho que rodar-los menos ou ter menos desses testes."
Se os testes indicam quais funcionalidades devem estar presentes...
... coverage vai indicar quais partes de código não tem nada a ver com as funcionalidades que vão ser entregues.
class Client:
def __init__(self, name):
self.name = name
Novo requisito: "somente aceitar nomes válidos, que tem 2 palavras ou mais."
def _multiple_names(name):
split_names = name.split(' ')
return len(split_names) > 1
def _validate_name(name):
if not _multiple_names(name):
raise Exception("Invalid name")
return name
class Client:
def __init__(self, name):
self.name = _validate_name(name)
import pytest
def test_single_name():
assert not _multiple_names('Cher')
def test_multiple_name():
assert _multiple_names('Julio Biason')
def test_valid_name():
_validate_name('Julio Biason')
def test_invalid_name():
with pytest.raises(Exception):
_validate_name('Cher')
def test_client_error():
with pytest.raises(Exception):
Client(name='Cher')
def test_client():
Client(name='Julio Biason')
$ pytest client.py
==== test session starts ====
rootdir: /home/jbiason/unitt, inifile:
collected 6 items
client.py ......
==== 6 passed in 0.03 seconds ====
$ pytest --cov=client client.py
==== test session starts ====
plugins: cov-2.4.0
collected 6 items
client.py ......
---- coverage: platform linux, python 3.4.3-final-0 ----
Name Stmts Miss Cover
-------------------------------
client.py 25 0 100%
==== 6 passed in 0.11 seconds ====
"Não podemos perder a Cher, a Xuxa, a Madonna, a Björk e o String como clientes!"
class Client:
def __init__(self, name):
self.name = name
==== FAILURES ====
____ test_client_error ____
def test_client_error():
with pytest.raises(Exception):
> Client(name='Cher')
E Failed: DID NOT RAISE <class 'Exception'>
client.py:37: Failed
==== 1 failed, 5 passed in 0.63 seconds ====
$ pytest client.py
==== test session starts ====
rootdir: /home/jbiason/unitt, inifile:
plugins: cov-2.4.0
collected 6 items
client.py ......
==== 6 passed in 0.03 seconds ====
$ pytest --cov=client client.py
==== test session starts ====
rootdir: /home/jbiason/unitt, inifile:
plugins: cov-2.4.0
collected 6 items
client.py ......
---- coverage: platform linux, python 3.4.3-final-0 ----
Name Stmts Miss Cover
-------------------------------
client.py 24 0 100%
==== 6 passed in 0.12 seconds ====
Encontre o erro.
100% de cobertura de testes é possível.
... desde que esteja disposto a escrever código que testa funcionalidades do usuário e não conformidade de arquitetura e código não coberto seja apagado.