Você está certo, seus testes não devem verificar se o random
módulo está fazendo seu trabalho; um unittest deve testar apenas a classe em si, não como ele interage com outro código (que deve ser testado separadamente).
É claro que é perfeitamente possível que seu código use random.randint()
errado; ou você está ligando random.randrange(1, self._sides)
e seu dado nunca gera o valor mais alto, mas esse seria um tipo diferente de inseto, que você não poderia pegar com um pouco mais unido. Nesse caso, sua die
unidade está funcionando como projetada, mas o design em si foi defeituoso.
Nesse caso, eu usaria zombaria para substituir a randint()
função e verifique apenas se ela foi chamada corretamente. O Python 3.3 e superior vem com o unittest.mock
módulo para lidar com esse tipo de teste, mas você pode instalar o mock
pacote externo em versões mais antigas para obter exatamente a mesma funcionalidade
import unittest
try:
from unittest.mock import patch
except ImportError:
# < python 3.3
from mock import patch
@patch('random.randint', return_value=3)
class TestDice(unittest.TestCase):
def _make_one(self, *args, **kw):
from die import Die
return Die(*args, **kw)
def test_standard_size(self, mocked_randint):
die = self._make_one()
result = die.roll()
mocked_randint.assert_called_with(1, 6)
self.assertEqual(result, 3)
def test_custom_size(self, mocked_randint):
die = self._make_one(sides=42)
result = die.roll()
mocked_randint.assert_called_with(1, 42)
self.assertEqual(result, 3)
if __name__ == '__main__':
unittest.main()
Com a zombaria, seu teste agora é muito simples; existem apenas 2 casos, realmente. A caixa padrão para uma matriz de 6 lados e a caixa dos lados personalizados.
Existem outras maneiras de substituir temporariamente a randint()
função no espaço para nome global de Die
, mas o mock
módulo facilita isso. O @mock.patch
decorador aqui se aplica a todos os métodos de teste no caso de teste; cada método de teste recebe um argumento extra, a random.randint()
função de simulação, para que possamos testar contra a simulação para ver se ela realmente foi chamada corretamente. O return_value
argumento especifica o que é retornado do mock quando é chamado, para que possamos verificar se o die.roll()
método realmente retornou o resultado 'aleatório' para nós.
Eu usei outra prática recomendada sem Python aqui: importe a classe em teste como parte do teste. O _make_one
método faz a importação e a instanciação dentro de um teste , para que o módulo de teste ainda seja carregado, mesmo se você cometer um erro de sintaxe ou outro erro que impeça a importação do módulo original.
Dessa forma, se você cometeu um erro no próprio código do módulo, os testes ainda serão executados; eles simplesmente falharão, informando sobre o erro no seu código.
Para deixar claro, os testes acima são simplistas ao extremo. O objetivo aqui não é testar o que random.randint()
foi chamado com os argumentos corretos, por exemplo. Em vez disso, o objetivo é testar se a unidade está produzindo os resultados certos, com base em determinadas entradas, onde essas entradas incluem os resultados de outras unidades que não estão sendo testadas. Ao zombar do random.randint()
método, você assume o controle sobre apenas outra entrada do seu código.
Nos testes do mundo real , o código real em sua unidade em teste será mais complexo; o relacionamento com as entradas passadas para a API e como outras unidades são chamadas ainda pode ser interessante ainda, e a zombaria lhe dará acesso a resultados intermediários, além de definir os valores de retorno para essas chamadas.
Por exemplo, no código que autentica os usuários em relação a um serviço OAuth2 de terceiros (uma interação de vários estágios), você deseja testar se seu código está passando os dados corretos para esse serviço de terceiros e simular respostas de erro diferentes que O serviço de terceiros retornaria, permitindo simular diferentes cenários sem a necessidade de criar um servidor OAuth2 completo. Aqui é importante testar se as informações de uma primeira resposta foram tratadas corretamente e foram passadas para uma chamada de segundo estágio, para que você queira ver se o serviço simulado está sendo chamado corretamente.