1
resposta

[Dúvida] Grupos de testes e Docstrings

Considerando que em diversas ocasiões é necessário criar mais de um teste para testar uma mesma função ou método considerando diferentes entradas e diferentes saídas, existe algum jeito de configurar grupos de teste? Digo isso pois no JavaScript é possível criar grupos de teste de acordo com um determinado contexto.

Neste caso faria sentido por exemplo criar um contexto chamado por exemplo "Bônus para funcionários de acordo com o valor do salário", dentro do qual poderiam haver o teste "Quando recebem 1000 deve retornar 100" e o "Quando recebe 1000000 deve retornar exception". Seria possível tal comportamento?


Outra duvida é acerca do uso de docstrings. No Python é possível usar ''' ''' para escrever a documentação de uma determinada classe, função ou método. Dito isso, seria possível usar as docstrings nos métodos de teste para que estas sejam exibidas quando os testes forem executados? Imagino que isso seria bom pois evitaria depender apenas do nome dos métodos para explicar as regras do teste em questão.

1 resposta

Olá, tudo bem?

Peço desculpas pela demora em obter um retorno.

Assim como no JavaScript, em Python também temos a possibilidade de criar suítes de testes que possuam um contexto em comum. Para isso, acoplamos este mesmo contexto separando por classes e arquivos, que serão localizados dentro da pasta tests.

Supondo que queremos fazer testes relacionados a clientes e a funcionários, neste caso, poderíamos ter dois arquivos: test_cliente e test_funcionario, onde, em cada arquivo teria uma classe com os testes necessários em cada ocasião.

Já para casos onde temos testes parecidos, mas que retornam valores diferentes, podemos utilizar o recurso da parametrização dos testes (@pytest.mark.parametrize), onde teremos um conjunto de tuplas com a saída esperada em cada cenário diferente. Tomando como exemplo o bônus do funcionário exemplificado por você, veja como fica em código ao utilizarmos o recurso da parametrização:

import pytest

resultados_esperados_no_teste = [
    (1000, 100),
    (1000000, Exception),
    (200, ValueError),
]

def calcular_bonus_de_acordo_com_salario(salario):
    if salario == 1000:
        return 100
    elif salario == 1000000:
        raise Exception("")
    else:
        raise ValueError("")

@pytest.mark.parametrize("salario,esperado", resultados_esperados_no_teste)
def test_calcular_bonus(salario, esperado):

    if esperado == Exception:
        with pytest.raises(Exception):
            calcular_bonus_de_acordo_com_salario(salario)
    elif esperado == ValueError:
        with pytest.raises(ValueError):
            calcular_bonus_de_acordo_com_salario(salario)
    else:
        assert calcular_bonus_de_acordo_com_salario(salario) == esperado

Já em relação às docstrings, podemos utilizá-las dentro dos métodos para usar uma descrição sucinta do objetivo do método, como mostro abaixo:

@pytest.mark.parametrize("salario,esperado", resultados_esperados_no_teste)
def test_calcular_bonus(salario, esperado):
    """Testes para o cálculo de bônus de acordo com o valor do salário"""

    if esperado == Exception:
        with pytest.raises(Exception):
            calcular_bonus_de_acordo_com_salario(salario)
    elif esperado == ValueError:
        with pytest.raises(ValueError):
            calcular_bonus_de_acordo_com_salario(salario)
    else:
        assert calcular_bonus_de_acordo_com_salario(salario) == esperado

No entanto, para exibir a documentação dos testes na execução, é necessário sobrescrever a função pytest_itemcollected, que é responsável por mostrar a exibição de um item de teste. Para isso, crie um arquivo chamado conftest.py dentro da pasta principal do projeto e coloque o conteúdo abaixo, que irá subscrever a função pytest_itemcollected:

def pytest_itemcollected(item):
    par = item.parent.obj
    node = item.obj
    pref = par.__doc__.strip() if par.__doc__ else par.__class__.__name__
    suf = node.__doc__.strip() if node.__doc__ else node.__name__
    if pref or suf:
        item._nodeid = ' '.join((pref, suf))

Dessa forma, ao executar o código através do comando pytest -v nome_do_test.py, as docstrings serão exibidas, como mostro na saída abaixo:

Testes para o cálculo de bônus de acordo com o valor do salário::::Testes para o cálculo de bônus de acordo com o valor do salário <- test_bonus.py PASSED 

Todavia, vale ressaltar que com a ausência dessa configuração e passando na execução apenas a opção -v (verbose -> pytest -v) será apresentado os valores que foram usados para o teste, o que pode ser mais ilustrativo do que a apresentação da docstring em alguns casos:

test_bonus.py::test_calcular_bonus[1000-100] PASSED                                                                                                                                                                                                                     
test_bonus.py::test_calcular_bonus[1000000-Exception] PASSED                                                                                                                                                                                                            
test_bonus.py::test_calcular_bonus[200-ValueError] PASSED       

Também reforço que quando estamos trabalhando com testes é comum que o nome da função seja longo, então não se preocupe. Os nomes longos irão ajudar a descrever com precisão o que está sendo testado e garantir a legibilidade dos testes.

Espero ter ajudado.

Conte sempre com o fórum da Alura para evoluir seus estudos.

Grande Abraço!

Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓. Bons Estudos!