Testando código – doctest

Em um post antigo, vimos o que são docstrings e para que servem. No post de hoje, veremos como utilizá-las para especificar testes sobre nossas funções.

Considere que estamos escrevendo um programa, e precisamos escrever uma função que calcule o dobro de um determinado número. Então, escrevemos o código:

def dobro(x):
    result = x * 2
    return result

Agora, para saber se está funcionando corretamente, vamos testar chamando a função dobro, passando como argumento alguns valores para os quais nós conhecemos o valor de retorno que a função deveria retornar:

>>> dobro(1)
2
>>> dobro(2)
4
>>> dobro(3)
6
>>> dobro(4)
8
>>> dobro(5)
10

Verificando visualmente os resultados, nos parece que a função está funcionando corretamente (e está, de fato). Daí, vem um colega e diz que não é necessário criarmos uma variável result, podendo retornar diretamente o retorno da expressão x * 2. Daí vamos editar nosso código para que se pareça com o código abaixo:

def dobro(x):
    return x * 2

Agora, teremos que rodar novamente os 5 testes acima e verificar, linha por linha, se o resultado está correto. Isso é chato, e também, em casos mais complexos, muito propenso a erros. Para não precisar rodar manualmente os testes e verificar visualmente se o resultado está correto, vamos utilizar o módulo doctest [1]. Com esse módulo, basta que colemos os testes (realizados no terminal interativo) dentro da docstring da função correspondente. Por exemplo, para aplicar doctests na nossa função dobro, vamos modificar o código para que se pareça com o código abaixo:

def dobro(x):
	"""
	Funcao que retorna o dobro do valor passado como argumento.
	>>> dobro(1)
	2
	>>> dobro(2)
	4
	>>> dobro(3)
	6
	>>> dobro(4)
	8
    >>> dobro(5)
    10
	"""
	return x * 2

Agora, vou executar os testes, chamando o módulo doctest pela linha de comando de um shell Linux (poderia ser por um terminal Windows/Mac):

user@host:~/ $ python -m doctest -v t.py
Trying:
 dobro(1)
Expecting:
 2
ok
Trying:
 dobro(2)
Expecting:
 4
ok
Trying:
 dobro(3)
Expecting:
 6
ok
Trying:
 dobro(4)
Expecting:
 8
ok
Trying:
 dobro(5)
Expecting:
 10
ok
1 items had no tests:
 t
1 items passed all tests:
 5 tests in t.dobro
5 tests in 2 items.
5 passed and 0 failed.
Test passed.

Ao chamar o módulo doctest pela linha de comando, passando como entrada o arquivo que contém a função dobro() (t.py, no caso), esse módulo vai varrer o código-fonte atual em busca de funções que contenham docstrings cujo conteúdo seja similar ao que aparece em uma tela de terminal interativo do Python. Ao se deparar com tal conteúdo (como por exemplo: >>> dobro(1)), o doctest vai executar tal código e ver se o resultado é igual ao que aparece na linha seguinte na docstring. Assim, se tivermos feito alguma alteração que quebrou o funcionamento da função, ao rodar o doctest, esse erro será acusado. Vamos ver isso na prática. Vou alterar a expressão de retorno da função dobro para x * 3:

def dobro(x):
    """
    Funcao que retorna o dobro do valor passado como argumento.
    >>> dobro(1)
    2
    >>> dobro(2)
    4
    >>> dobro(3)
    6
    >>> dobro(4)
    8
    >>> dobro(5)
    10
    """
    return x * 3

Agora, vou rodar o código acima e vamos ver o resultado.


user@host:~/ $ python -m doctest -v t.py
 Trying:
 dobro(1)
 Expecting:
 2
 **********************************************************************
 File "t.py", line 4, in t.dobro
 Failed example:
 dobro(1)
 Expected:
 2
 Got:
 3
 Trying:
 dobro(2)
 Expecting:
 4
 **********************************************************************
 File "t.py", line 6, in t.dobro
 Failed example:
 dobro(2)
 Expected:
 4
 Got:
 6
 Trying:
 dobro(3)
 Expecting:
 6
 **********************************************************************
 File "t.py", line 8, in t.dobro
 Failed example:
 dobro(3)
 Expected:
 6
 Got:
 9
 Trying:
 dobro(4)
 Expecting:
 8
 **********************************************************************
 File "t.py", line 10, in t.dobro
 Failed example:
 dobro(4)
 Expected:
 8
 Got:
 12
 Trying:
 dobro(5)
 Expecting:
 10
 **********************************************************************
 File "t.py", line 12, in t.dobro
 Failed example:
 dobro(5)
 Expected:
 10
 Got:
 15
 1 items had no tests:
 t
 **********************************************************************
 1 items had failures:
 5 of 5 in t.dobro
 5 tests in 2 items.
 0 passed and 5 failed.
 ***Test Failed*** 5 failures.
 

Ao final, podemos ver um mini-relatório da execução.

Assim, sempre que for preciso alterar minha função dobro(), não precisarei rodar e conferir os resultados manual e visualmente. Basta manter a doctring dentro da função e executar o o módulo doctest passando como entrada o arquivo que contém minha função, que as verificações serão realizadas por este.

[1] http://docs.python.org/library/doctest.html

Anúncios

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s