"Unit" em "Unit Tests"

Me
Eu faço perguntas em reuniões que eu não sei nada e reunião explode; não é de propósito
... mas hoje eu vim botar os filho dos outro no go horse.
TDD: Where it went wrong

Ian Cooper: "TDD, where did it all go wrong"

Apresentação de Ian Cooper ressoou muito com experiências feitas com TDD puro e "testes de ponta-a-ponta".

Mas antes...

Quem já...

  • ... falou de "testes de unidade"?
  • ... discutiu a "unidade" dos testes de unidade?
Errow
Errou rude

Exemplo


class Client:
    def __init__(self, name):
        self.name = name
                        

Exemplo

Novo requisito: "somente aceitar nomes válidos, que tem 2 palavras ou mais."

Exemplo

SOLID principles:

  • SRP - Single Responsability Principle
  • OCP - Open/closed principle
  • LSP - Liskov substitution principle (design by contract)
  • ISP - Interface Segreation Principle
  • DIP - Dependency Inversion Principle

Exemplo


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)
                        

Exemplo


import pytest

def test_single_name():
    assert not _multiple_names('Cher')

def test_multiple_name():
    assert _multiple_names('Julio Biason')
                        

Exemplo


def test_valid_name():
    _validate_name('Julio Biason')

def test_invalid_name():
    with pytest.raises(Exception):
        _validate_name('Cher')
                        

Exemplo


def test_client_error():
    with pytest.raises(Exception):
        Client(name='Cher')

def test_client():
    Client(name='Julio Biason')
                        

Exemplo


$ pytest client.py
==== test session starts ====
rootdir: /home/jbiason/unitt, inifile:
collected 6 items

client.py ......

==== 6 passed in 0.03 seconds ====
                        

Exemplo


$ 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 ====
                        

Exemplo

"Não podemos perder a Cher, a Xuxa, a Madonna, a Björk e o String como clientes!"

Exemplo


class Client:
    def __init__(self, name):
        self.name = name
                        

Exemplo


==== 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 ====
                        

Exemplo


$ 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 ====
                        

Exemplo


$ 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 ====
                        

Exemplo

Encontre o erro.

TDD

Kent Beck:

  • "Run in isolation", nothing more, nothing less.
  • "Avoid testing implementation details, test behaviours"

TDD

Discussões como "qual a unidade a ser testada" é que geraram coisas como BDD e ATDD (Acceptance Test-Driven Development).

TDD

Reddit: Devo escrever testes para a validação interna do Django?

SIM!

TDD

Nossos testes End-to-End.

TDD

The TDD lifecycle

TDD

SOLID principles:

  • SRP - Single Responsability Principle
  • OCP - Open/closed principle
  • LSP - Liskov substitution principle (design by contract)
  • ISP - Interface Segreation Principle
  • DIP - Dependency Inversion Principle

Funciona para aplicações inteiras; veja VIM vs NeoVim.

Resumo

  • Escreva testes que verifiquem requisitos, não a implementação do requisito
  • Implementação pode mudar, os testes não deveriam.
  • Garanta que o teste dependa apenas de si mesmo e não de outros testes.
  • Use cobertura (coverage) para identificar código a ser removido, não para escrever mais testes.

Perguntas?