Primeiros passos com testes unitários em Python

Se você precisa escrever teste de unidades em Python e não sabe por onde começar, este artigo é para você!

Em Python, quando queremos escrever testes unitários podemos lançar mãos desde um simples assert, passando por funções auxiliares até um framework de testes unitários completo. Neste artigo vou mostrar rapidamente como funciona o statement assert e mostrar também algumas funções que também podem ser úteis, termino mostrando um "Hello world" do Unit testing framework.

assert

Em Python podemos fazer simples asserções utilizando o statement assert.

assert True

Se executarmos no terminal assert True, o comando fica em silêncio, nada responde. Esse é o comportamento esperado, pois a asserção teve sucesso e o "silêncio" é o sintoma de que tudo está funcionando.

Se executarmos assert False o comando dispara um erro...

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

O statement aceita como segundo parâmetro uma string que pode ser um mensagem explicativa e é exibida quando a asserção falha.

>>> assert False, "mensagem explicativa"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: mensagem explicativa

Para exemplificar o funcionamento do statement, veja o trecho de código abaixo.

b = 150
expressao = 100 > b
mensagem  = "100 deve ser maior que 'b'"
assert expressao, mensagem

Obtemos como como resposta...

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: 100 deve ser maior que b

O que vem depois ?

Se ao invés do "assert", você quisesse utilizar uma função, por exemplo, test() para realizar pequenos testes, como seria a implementação dessa função?

Que tal o exemplo abaixo?

def test(expression1, expression2):
    if expression1 == expression2:
        return 'Pass'
    else:
        return 'Fail'

Já o tutorial do Goole sugere uma função igualmente simples, porém, ligeiramente mais sofisticada, veja código seguinte.

def test(got, expected):

  if got == expected:
    prefix = ' OK '
  else:
    prefix = '  X '

  print("%s got: %s expected: %s" % (prefix, repr(got), repr(expected)))

Pesquisando na web encontrei mais dois exemplos que merecem nossa atenção.

O primeiro deles, você confere no código abaixo. Repare que temos a utilização do objeto sys e que a saída dessa função é bem mais elaborada, ela alerta até o número da linha onde o erro foi encontrado.

import sys

def test(did_pass):
    """  Print the result of a test.  """
    linenum = sys._getframe(1).f_lineno   # Get the caller's line number.
    if did_pass:
        msg = "Test at line {0} ok.".format(linenum)
    else:
        msg = ("Test at line {0} FAILED.".format(linenum))
    print(msg)

O segundo exemplo é muito parecido com o anterior, até parece que o autor se baseou no primeiro exemplo e implementou sua própria customização. Pequenos detalhes foram alterados.

def test(actual, expected):
    import sys
    linenum = sys._getframe(1).f_lineno   # get the caller's line number.
    if (expected == actual):
        msg = "Test on line {0} passed.".format(linenum)
    else:
        msg = ("Test on line {0} failed. Expected '{1}', but got '{2}'."
                                     . format(linenum, expected, actual))
    print(msg)

Aí você percebe que precisa de um framework de verdade para escrever seus testes unitários...

Unit Testing Framework

O Unit Testing Framework pode ser o que você esteja procurando.

Longe de querer se aprofundar no framework (leia a documentação), vou apenas mostrar dois exemplos do tipo "Hello world".

Abaixo um exemplo demonstrando como testar uma simples função.

import unittest

def fun(x):
    return x + 1

class MyTest(unittest.TestCase):
    def test(self):
        self.assertEqual(fun(3), 4)

if __name__ == '__main__':
    unittest.main()

O resultado de python foo.py você confere abaixo.

.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

O exemplo seguinte demonstra como testar uma pequena classe.

import unittest

class MyFun:
    def fun(self, n):
        return n + 1

class MyFunTest(unittest.TestCase):
    def testFun(self):
        obj = MyFun()
        self.assertEqual(obj.fun(3), 4)

if __name__ == '__main__':
    unittest.main()

O resultado é semelhante ao anterior.

.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

Comentários

comments powered by Disqus