Estou usando pythons mock.patch e gostaria de alterar o valor de retorno para cada chamada. Aqui está a ressalva: a função que está sendo corrigida não possui entradas, portanto, não posso alterar o valor de retorno com base na entrada.
Aqui está o meu código para referência.
def get_boolean_response():
response = io.prompt('y/n').lower()
while response not in ('y', 'n', 'yes', 'no'):
io.echo('Not a valid input. Try again'])
response = io.prompt('y/n').lower()
return response in ('y', 'yes')
Meu código de teste:
@mock.patch('io')
def test_get_boolean_response(self, mock_io):
#setup
mock_io.prompt.return_value = ['x','y']
result = operations.get_boolean_response()
#test
self.assertTrue(result)
self.assertEqual(mock_io.prompt.call_count, 2)
io.prompt
é apenas uma versão independente da plataforma (python 2 e 3) de "input". Então, finalmente, estou tentando zombar da entrada dos usuários. Eu tentei usar uma lista para o valor de retorno, mas isso não parece funcionar.
Você pode ver que, se o valor de retorno for algo inválido, receberei apenas um loop infinito aqui. Então, preciso de uma maneira de alterar o valor de retorno, para que meu teste realmente termine.
(outra maneira possível de responder a essa pergunta poderia ser explicar como eu poderia imitar a entrada do usuário em um teste de unidade)
Não estou enganado com esta questão principalmente porque não tenho a capacidade de variar as entradas.
Um dos comentários da resposta sobre esta pergunta está na mesma linha, mas nenhuma resposta / comentário foi fornecido.
fonte
response is not 'y' or 'n' or 'yes' or 'no'
em não fazer o que você pensa que faz. Consulte Como faço para testar uma variável em relação a vários valores? e você não deve usaris
para comparar valores de cadeia, use==
para comparar valores , não para identidades de objetos.is
para comparar literais de strings. Não faça isso. O fato de funcionar (algumas vezes) é apenas um detalhe de implementação no CPython. Além disso,response is not 'y' or 'n' or 'yes' or 'no'
provavelmente não está fazendo o que você pensa que é ...Respostas:
Você pode atribuir um iterável a
side_effect
, e a simulação retornará o próximo valor na sequência sempre que for chamado:Citando a
Mock()
documentação :Como um aparte, o teste
response is not 'y' or 'n' or 'yes' or 'no'
vai não trabalhar; você está perguntando se a expressão(response is not 'y')
é verdadeira ou'y'
verdadeira (sempre é o caso, uma seqüência de caracteres não vazia é sempre verdadeira) etc. As várias expressões de ambos os lados dosor
operadores são independentes . Consulte Como faço para testar uma variável em relação a vários valores?Você também não deve usar
is
para testar uma string. O intérprete CPython pode reutilizar objetos de string em determinadas circunstâncias , mas não é com esse comportamento que você deve contar.Como tal, use:
em vez de; isso usará testes de igualdade (
==
) para determinar se fazresponse
referência a uma sequência com o mesmo conteúdo (valor).O mesmo se aplica a
response == 'y' or 'yes'
; use emresponse in ('y', 'yes')
vez disso.fonte
mock
? Existe uma maneira de usar o patch com MagicMock como eu estou fazendo com o mock padrão?Mock
classe stardard .m.side_effect = iter(['foo', 'bar', 'baz'])
).lambda
(a), não aMagicMock
. Um objeto de função não pode ter propriedades, portanto, oside_effect
atributo deve ser iterável. Você não deve especificar o método assim. Melhor usomock.patch.object(requests.Session, 'post')
; isso resulta em um objeto patcher que especifica automaticamente automaticamente o método e suportaside_effect
corretamente.StopIteration
é gerado. Você pode usar qualquer iteradoritertools.chain(['Foo'], itertools.repeat('Bar'))
para produzirFoo
uma vez e depois produzir para sempreBar
.