Paulo Henrique Rodrigues Pinheiro

Um blog sobre programação para programadores!


Usando strings e doctest em Python2 e Python3 simultaneamente.

Usando strings de uma forma que funciona tanto no Python2 como no Python3, especialmente quando fazendo testes com doctest.

Descrição

Usando doctest

É muito simples, pois na própria docstring de sua função você já escreve os testes. Por exemplo:


# encoding: utf-8

def dobro(x):
    """Retorna o dobro do número passado como argumento

    >>> dobro(2)
    4
    >>> dobro(0)
    0
    >>> dobro(1.5)
    3.0
    >>> dobro(-2)
    -4
    """
    return (x*2)

if __name__ == '__main__':
    import doctest
    doctest.testmod(verbose=True)

Esse exemplo funciona tanto em Python2 (por isso o encoding na primeira linha) como no Python3. Salvando como /tmp/test1.py:


$ python /tmp/a.py
Trying:
    dobro(2)
Expecting:
    4
ok
Trying:
    dobro(0)
Expecting:
    0
ok
Trying:
    dobro(1.5)
Expecting:
    3.0
ok
Trying:
    dobro(-2)
Expecting:
    -4
ok
1 items had no tests:
    __main__
1 items passed all tests:
   4 tests in __main__.dobro
4 tests in 2 items.
4 passed and 0 failed.
Test passed.

Tente executar também python3 /tmp/teste1.py. A saída deve ser a mesma.

Maravilhoso! Meu problema veio quando tive que fazer testes com funções que retornavam strings.


# encoding: utf-8

import doctest

def cumprimenta(fulano):
    """Cumprimenta com "Olá, Fulano!". Se fulano for vazio retorna "Olá."

    >>> cumprimenta('')
    'Olá.'
    >>> cumprimenta('Paulo')
    'Olá, Paulo!'
    """
    return 'Olá, %s!'%fulano if fulano else 'Olá.'

doctest.testmod()

Com PY2 temos essa saída:


$ python2 /tmp/test2.py
**********************************************************************
File "/tmp/test2.py", line 8, in __main__.cumprimenta
Failed example:
    cumprimenta('')
Expected:
    'Olá.'
Got:
    'Ol\xc3\xa1.'
**********************************************************************
File "/tmp/test2.py", line 10, in __main__.cumprimenta
Failed example:
    cumprimenta('Paulo')
Expected:
    'Olá, Paulo!'
Got:
    'Ol\xc3\xa1, Paulo!'
**********************************************************************
1 items had failures:
   2 of   2 in __main__.cumprimenta
***Test Failed*** 2 failures.

Com PY3 temos essa:


$ python3 /tmp/test2.py
$

Ou seja, tudo certo.

Aqui entramos no terrível mundo das codificações de caracteres em PY2. Nem vou mostrar o que tentei, pois é ridículo. Pesquisando com mais calma achei essa questão no StackOverflow:

http://stackoverflow.com/questions/1733414/how-do-i-include-unicode-strings-in-python-doctests

Moleza! E agora? Testemos isso:


# encoding: utf-8

from __future__ import print_function

import doctest

def cumprimenta(fulano):
    """Cumprimenta com "Olá, Fulano!". Se fulano for vazio retorna "Olá."

    >>> print(cumprimenta(''))
    Olá.
    >>> print(cumprimenta('Paulo'))
    Olá, Paulo!
    """
    return 'Olá, %s!'%fulano if fulano else 'Olá.'

doctest.testmod()

Adicionamos o modulo future para que o print seja uma função no PY2.