assert_has_calls
é outra abordagem para esse problema.
Dos documentos:
assert_has_calls (chamadas, any_order = False)
afirmar que a simulação foi chamada com as chamadas especificadas. A lista mock_calls é verificada para as chamadas.
Se any_order for False (o padrão), as chamadas deverão ser seqüenciais. Pode haver chamadas extras antes ou depois das chamadas especificadas.
Se any_order for True, as chamadas poderão estar em qualquer ordem, mas todas deverão aparecer em mock_calls.
Exemplo:
>>> from unittest.mock import call, Mock
>>> mock = Mock(return_value=None)
>>> mock(1)
>>> mock(2)
>>> mock(3)
>>> mock(4)
>>> calls = [call(2), call(3)]
>>> mock.assert_has_calls(calls)
>>> calls = [call(4), call(2), call(3)]
>>> mock.assert_has_calls(calls, any_order=True)
Fonte: https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock.assert_has_calls
tuple
:isinstance(mock.call(1), tuple)
dáTrue
. Eles também adicionaram alguns métodos e atributos.side_effect
Normalmente, eu não me importo com a ordem das ligações, apenas com o que elas aconteceram. Nesse caso, eu combino
assert_any_call
com uma afirmação sobrecall_count
.Acho que fazer dessa maneira é mais fácil de ler e entender do que uma grande lista de chamadas passadas em um único método.
Se você se importa com o pedido ou espera várias chamadas idênticas,
assert_has_calls
pode ser mais apropriado.Editar
Desde que publiquei esta resposta, repensei minha abordagem aos testes em geral. Eu acho que vale a pena mencionar que, se o seu teste está ficando complicado, você pode estar testando inadequadamente ou ter um problema de design. As zombarias são projetadas para testar a comunicação entre objetos em um design orientado a objetos. Se o seu design não for orientado a objeções (como em mais processuais ou funcionais), a simulação pode ser totalmente inadequada. Você também pode ter muita coisa acontecendo dentro do método ou pode estar testando detalhes internos que devem ser deixados sem zerar. Desenvolvi a estratégia mencionada neste método quando meu código não era muito orientado a objetos e acredito que também estava testando detalhes internos que seria melhor deixar de serem desmembrados.
fonte
do() if TEST_ENV=='prod' else dont()
), é conseguido facilmente zombando da maneira sugerida. um efeito colateral disso é ser para manter testes por versões (alterações de código digamos entre google search v1 API e v2, seu código irá testar a versão 1 não importa qual)Você pode usar o
Mock.call_args_list
atributo para comparar parâmetros com chamadas de método anteriores. Isso em conjunto com oMock.call_count
atributo deve lhe dar controle total.fonte
assert_has_calls
verifica apenas se as chamadas esperadas foram feitas, mas não se essas são as únicas.Eu sempre tenho que procurar isso uma e outra vez, então aqui está a minha resposta.
Afirmando várias chamadas de método em diferentes objetos da mesma classe
Suponha que tenhamos uma classe de serviço pesado (da qual queremos zombar):
Aqui está um código que usa duas instâncias da
HeavyDuty
classe:Agora, aqui está um caso de teste para a
heavy_work
função:Estamos zombando da
HeavyDuty
classeMockHeavyDuty
. Para declarar chamadas de método provenientes de todas asHeavyDuty
instâncias às quais temos que nos referirMockHeavyDuty.return_value.assert_has_calls
, em vez deMockHeavyDuty.assert_has_calls
. Além disso, na lista deexpected_calls
nós temos que especificar qual nome de método estamos interessados em afirmar chamadas. Portanto, nossa lista é feita de chamadas paracall.do_work
, em vez de simplesmentecall
.O exercício do caso de teste mostra que é bem-sucedido:
Se modificarmos a
heavy_work
função, o teste falhará e produzirá uma mensagem de erro útil:Declarando várias chamadas para uma função
Para contrastar com o acima, aqui está um exemplo que mostra como simular várias chamadas para uma função:
Existem duas diferenças principais. A primeira é que, ao zombar de uma função, configuramos nossas chamadas esperadas usando
call
, em vez de usarcall.some_method
. A segunda é que recorremos ,assert_has_calls
emmock_work_function
vez de continuarmock_work_function.return_value
.fonte