A atividade de testar software é uma tarefa repetitiva, demorada e tediosa. Por isso, surgiram várias ferramentas para automatizar testes. Existem dois módulos para testes automatizados que acompanham o Python: doctest e unittest.
O módulo doctest usa as Doc Strings que estão presentes no código para definir os testes do código. A função testmod()
do doctest procura por um trecho de texto seja semelhante a uma sessão interativa de Python, executa a mesma sequência de comandos, analisa a saída e faz um relatório dos testes que falharam, com os erros encontrados.
In [6]:
"""
Implementa Fibonacci.
"""
def fib(n):
"""Fibonacci:
Se n <= 1, fib(n) = 1
Se n > 1, fib(n) = fib(n - 1) + fib(n - 2)
Exemplos de uso:
>>> fib(0)
1
>>> fib(1)
1
>>> fib(10)
100
>>> [ fib(x) for x in xrange(10) ]
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
>>> fib('')
Traceback (most recent call last):
File "<input>", line 1, in ?
File "<input>", line 19, in fib
TypeError
>>>
"""
if not type(n) is int:
raise TypeError
if n > 1:
return fib(n - 1) + fib(n - 2)
else:
return 1
def _doctest():
"""
Evoca o doctest.
"""
import doctest
doctest.run_docstring_examples(fib, globals())
if __name__ == "__main__":
_doctest()
Se todos os testes forem bem sucedidos, não haverá relatório dos testes.
A saída do código acima é um exemplo de relatório de erros dos testes (a Doc String foi alterada de propósito para gerar um erro).
Usando o módulo unittest, os testes são criados através de uma subclasse da classe unittest.TestCase. Os testes são definidos como métodos da subclasse. Os métodos precisam ter seus nomes iniciando com test
para que sejam identificados como rotinas de teste.
Os métodos de teste devem evocar ao terminar um dos métodos:
Se houver um método chamado setUp, este será executado antes de cada teste, assim é possível reinicializar variáveis e garantir que um teste não prejudique o outro. O final dos testes, o unittest gera o relatório com os resultados encontrados.
Exemplo:
In [12]:
"""
Usa unittest para testar fib.py.
"""
import fib
import unittest
class TestSequenceFunctions(unittest.TestCase):
def setUp(self):
self.seq = range(10)
def test0(self):
self.assertEqual(fib.fib(0), 1)
def test1(self):
self.assertEqual(fib.fib(1), 1)
def test10(self):
self.assertEqual(fib.fib(10), 89)
def testseq(self):
fibs = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
for x, y in zip(fibs, [ fib.fib(x) for x in self.seq ]):
self.assert_(x is y)
def testtype(self):
self.assertRaises(TypeError, fib.fib, '')
if __name__ == '__main__':
suite = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions)
unittest.TextTestRunner(verbosity=2).run(suite)
Exemplo de relatório com erros:
..F..
======================================================================
FAIL: test10 (__main__.TestSequenceFunctions)
----------------------------------------------------------------------
Traceback (most recent call last):
File "unittest1.py", line 22, in test10
self.assertEqual(fib.fib(10), 89)
AssertionError: 100 != 89
----------------------------------------------------------------------
Ran 5 tests in 0.000s
FAILED (failures=1)
No relatório, o terceiro teste falhou, pois fib.fib(10)
retornou 100 ao invés de 89, como seria o esperado.
O unittest oferece uma solução muito semelhante a bibliotecas de testes implementadas em outras linguagens, enquanto o doctest é mais simples de usar e se integra bem com a documentação (as sessões do doctest podem servir como exemplos de uso).
In [ ]:
In [1]:
Out[1]: