O Py.test tem um excelente recurso chamado fixtures , que é uma forma pítônica de fazer injeção de dependência.
Exemplo rápido:
from random import randint
import pytest
@pytest.fixture
def number():
return randint(10)
@pytest.fixture
def structure(number):
return {'name': 'something',
'number': number}
def test_something(structure, number):
assert structure['number'] == number
O número aleatório será gerado apenas uma vez e, durante o teste, será sempre aquele número onde quer que seja injetado. Portanto, aqui o structure
dispositivo vê o mesmo number
que test_something
. Mas se o executarmos novamente, um novo número será gerado.
Isso é ótimo se você deseja gerar um único dado aleatório e verificá-lo mais tarde. Mas muitas vezes você realmente precisa de várias peças de dados aleatórios, e você não quer criar dispositivos elétricos como random_number1
, random_number2
etc.
Uma boa estratégia que descobri que funciona é, em vez de fazer com que o aparelho retorne os dados diretamente, em vez disso, o aparelho retorna uma função que tem acesso a outros aparelhos e que mantém o controle do que é gerado.
Isso se parece com o seguinte exemplo:
@pytest.fixture
def number():
return randint(10)
@pytest.fixture
def structure(number):
def _structure(name):
'''This function gets injected'''
retval = {
'name': name,
'number': randint(number, 20)
}
# register the result in the function
_structure.results[name] = retval
return retval
# before injecting, we create the registry
# on the function
_structure.results = {}
return _structure
@pytest.fixture
def big_structure(structure):
return {
'foo': structure('bar')
}
Os pontos principais são:
- Faça com que o aparelho retorne uma função, em vez dos dados
- A função obtém acesso a quaisquer outros acessórios que você deseja (aqui, usamos o
number
acessório como um piso para um novo número aleatório. - Adicione um atributo de registro à função, para controlar os resultados
def test_something(structure, number, big_structure):
result = structure('some_name')
assert result['number'] >= number
assert structure.results['some_name'] == result
assert structure.results['bar'] == big_structure['foo']
Por que a _structure
função registra seus próprios resultados? Porque você pode precisar usar o structure
acessório em outros acessórios. Aqui big_structure
usa structure
e se quisermos saber o que foi gerado, basta olhar no registro.
Além disso, como a função é criada por teste, o registro é apagado automaticamente para cada teste.