Como testar o seguinte código com zombarias (usando zombarias, o decorador de patches e sentinelas fornecidos pela estrutura Mock de Michael Foord ):
def testme(filepath):
with open(filepath, 'r') as f:
return f.read()
python
mocking
with-statement
Daryl Spitzer
fonte
fonte
Respostas:
A maneira de fazer isso foi alterada no mock 0.7.0, que finalmente suporta a zombaria dos métodos do protocolo python (métodos mágicos), principalmente usando o MagicMock:
http://www.voidspace.org.uk/python/mock/magicmock.html
Um exemplo de simulação aberta como um gerenciador de contexto (na página de exemplos na documentação da simulação):
fonte
__enter__
e também__exit__
zomba de objetos - a última abordagem está desatualizada ou ainda é útil?file
se foi!mock_open
faz parte damock
estrutura e é muito simples de usar.patch
usado como contexto retorna o objeto usado para substituir o corrigido: você pode usá-lo para simplificar seu teste.Python 3.x
Use em
builtins
vez de__builtin__
.Python 2.7
mock
não faz parteunittest
e você deve corrigir__builtin__
Caso decorador
Se você usasse
patch
como decorador, usandomock_open()
o resultado de s comonew
patch
argumento, pode ser um pouco estranho.Nesse caso, é melhor usar o
new_callable
patch
argumento do e lembre-se de que todos os argumentos extras quepatch
não usarem serão passados paranew_callable
funcionar como descrito napatch
documentação .Por exemplo, a versão decorada para o Python 3.x é:
Lembre-se de que, neste caso
patch
, o objeto simulado será adicionado como argumento de sua função de teste.fonte
with patch("builtins.open", mock_open(read_data="data")) as mock_file:
conversão pode ser convertida em sintaxe de decorador? Eu tentei, mas não tenho certeza do que preciso passar@patch("builtins.open", ...)
como segundo argumento.return_value
demock_open
para outro objeto de simulação e afirmar o segundoreturn_value
), mas funcionou adicionandomock_open
comonew_callable
.six
módulo para ter ummock
módulo consistente . Mas não sei se ele mapeia tambémbuiltins
em um módulo comum.Com as versões mais recentes do mock, você pode usar o realmente útil mock_open helper:
fonte
.write
chamadas?handle.write.assert_any_call()
. Você também pode usarhandle.write.call_args_list
para receber cada chamada, se o pedido for importante.m.return_value.write.assert_called_once_with('some stuff')
é melhor imo. Evita o registro de uma chamada.Mock.call_args_list
é mais seguro do que chamar qualquer um dosMock.assert_xxx
métodos. Se você digitar incorretamente qualquer um dos últimos, sendo atributos de Mock, eles sempre serão silenciosamente transmitidos.Para usar mock_open para um arquivo simples
read()
(o snippet mock_open original já fornecido nesta página é mais voltado para gravação):Observe que, de acordo com os documentos de mock_open, isso é especificamente para
read()
, portanto, não funcionará com padrões comuns comofor line in f
, por exemplo.Usa python 2.6.6 / mock 1.0.1
fonte
for line in opened_file:
tipo de código. Tentei experimentar o iterável StringIO que implementa__iter__
e usa isso em vez demy_text
, mas sem sorte.read()
que não funcione no seufor line in opened_file
caso; Eu editei o post para esclarecerfor line in f:
suporte ao @EvgeniiPuchkaryov pode ser obtido trocando o valor de retornoopen()
como um objeto StringIO .with open("any_string") as f: print f.read()
A resposta principal é útil, mas eu a expandi um pouco.
Se você deseja definir o valor do seu objeto de arquivo (o
f
inas f
) com base nos argumentos passados para,open()
aqui está uma maneira de fazê-lo:Basicamente,
open()
retornará um objeto ewith
o chamará__enter__()
.Para zombar corretamente, precisamos zombar
open()
para retornar um objeto zombado. Esse objeto simulado deve então simular a__enter__()
chamada (MagicMock
fará isso por nós) para retornar o objeto de dados / arquivo simulado que queremos (daímm.__enter__.return_value
). Fazer isso com 2 zombarias da maneira acima nos permite capturar os argumentos passadosopen()
e passá-los ao nossodo_something_with_data
método.Passei um arquivo simulado inteiro como uma string
open()
e fiqueido_something_with_data
assim:Isso transforma a string em uma lista para que você possa fazer o seguinte como faria com um arquivo normal:
fonte
__enter__
? Definitivamente, parece mais um hack do que uma maneira recomendada.Eu posso estar um pouco atrasado para o jogo, mas isso funcionou para mim ao chamar
open
outro módulo sem precisar criar um novo arquivo.test.py
MyObj.py
Ao aplicar um patch à
open
função dentro do__builtin__
módulomock_open()
, posso simular a gravação em um arquivo sem criar um.Nota: Se você estiver usando um módulo que usa o cython, ou se o seu programa depende do cython de qualquer forma, será necessário importar o
__builtin__
módulo do cython, incluindoimport __builtin__
na parte superior do arquivo. Você não poderá zombar do universal__builtin__
se estiver usando o cython.fonte
import __builtin__
ao meu módulo de teste. Este artigo ajudou a esclarecer por que essa técnica funciona tão bem quanto: ichimonji10.name/blog/6Para corrigir a função open () interna com o mais unido:
Isso funcionou para um patch para ler uma configuração do json.
O objeto simulado é o objeto io.TextIOWrapper retornado pela função open ()
fonte
Se você não precisar de mais nenhum arquivo, poderá decorar o método de teste:
fonte