Aşağıdaki kodu alaylarla nasıl test edebilirim (alay, yama dekoratörü ve Michael Foord'un Mock çerçevesi tarafından sağlanan nöbetçi kullanarak ):
def testme(filepath):
with open(filepath, 'r') as f:
return f.read()
Aşağıdaki kodu alaylarla nasıl test edebilirim (alay, yama dekoratörü ve Michael Foord'un Mock çerçevesi tarafından sağlanan nöbetçi kullanarak ):
def testme(filepath):
with open(filepath, 'r') as f:
return f.read()
Yanıtlar:
Bunu yapmanın yolu, özellikle MagicMock'u kullanarak python protokol yöntemlerini (sihirli yöntemler) taklit etmeyi destekleyen sahte 0.7.0'da değişti:
http://www.voidspace.org.uk/python/mock/magicmock.html
Bağlam yöneticisi olarak açık alaycı örneği (alay dokümanındaki örnekler sayfasından):
>>> open_name = '%s.open' % __name__
>>> with patch(open_name, create=True) as mock_open:
... mock_open.return_value = MagicMock(spec=file)
...
... with open('/some/path', 'w') as f:
... f.write('something')
...
<mock.Mock object at 0x...>
>>> file_handle = mock_open.return_value.__enter__.return_value
>>> file_handle.write.assert_called_with('something')
__enter__ve __exit__nesneleri açıkça ayarlayan ve alay eden bağlam yöneticisi örneğinden çok daha basit görünüyor - ikinci yaklaşım güncel değil mi, yoksa hala faydalı mı?
filegitti!
mock_openmockçerçevenin bir parçasıdır ve kullanımı çok basittir. patchbağlam olarak kullanıldığında yamalı olanı değiştirmek için kullanılan nesneyi döndürür: bunu testinizi basitleştirmek için kullanabilirsiniz.
Yerine builtinskullanın __builtin__.
from unittest.mock import patch, mock_open
with patch("builtins.open", mock_open(read_data="data")) as mock_file:
assert open("path/to/open").read() == "data"
mock_file.assert_called_with("path/to/open")
mockbir parçası değil unittestve yama yapmalısın__builtin__
from mock import patch, mock_open
with patch("__builtin__.open", mock_open(read_data="data")) as mock_file:
assert open("path/to/open").read() == "data"
mock_file.assert_called_with("path/to/open")
Eğer patchdekoratör olarak mock_open()'s sonucunu kullanarak kullanırsanız new patchargümanı biraz tuhaf olabilir.
Bu durumda, new_callable patch'argümanını kullanmak ve kullanmayan her fazladan argümanın dokümantasyonda açıklandığı gibi işlev patchgöreceğini hatırlamak daha iyidir .new_callablepatch
patch (), rastgele anahtar kelime bağımsız değişkenleri alır. Bunlar inşaatta Mock'a (veya new_callable) aktarılacaktır.
Örneğin Python 3.x için dekore edilmiş sürüm :
@patch("builtins.open", new_callable=mock_open, read_data="data")
def test_patch(mock_file):
assert open("path/to/open").read() == "data"
mock_file.assert_called_with("path/to/open")
Bu durumda patchsahte nesneyi test fonksiyonunuzun argümanı olarak ekleyeceğini unutmayın .
with patch("builtins.open", mock_open(read_data="data")) as mock_file:dekoratör sözdizimine dönüştürülebilir mi? Denedim, ama @patch("builtins.open", ...) ikinci argüman olarak neye girmem gerektiğinden emin değilim .
return_valuebir mock_openbaşka sahte nesnesine ve ikinci alay en assert return_value), ancak ekleyerek çalıştı mock_openolarak new_callable.
six, tutarlı bir mockmodüle sahip olmak için modüle bakın. Ama builtinsortak bir modülde de eşleşip eşlenmediğini bilmiyorum .
Mock'un en son sürümleriyle, gerçekten yararlı mock_open yardımcısını kullanabilirsiniz:
mock_open (mock = Yok, read_data = Yok)
Açık kullanım yerine alay oluşturmak için bir yardımcı işlevi. Doğrudan çağrılan veya içerik yöneticisi olarak kullanılan açık işler için çalışır.
Sahte argüman yapılandırılacak sahte nesnedir. Hiçbiri (varsayılan) değilse, API standart dosya tanıtıcılarında kullanılabilen yöntem veya özniteliklerle sınırlı olacak şekilde bir MagicMock oluşturulacaktır.
read_data, dosya tanıtıcısının okuma yönteminin döndüreceği bir dizedir. Bu, varsayılan olarak boş bir dizedir.
>>> from mock import mock_open, patch
>>> m = mock_open()
>>> with patch('{}.open'.format(__name__), m, create=True):
... with open('foo', 'w') as h:
... h.write('some stuff')
>>> m.assert_called_once_with('foo', 'w')
>>> handle = m()
>>> handle.write.assert_called_once_with('some stuff')
.writeçağrı olup olmadığını nasıl kontrol edersiniz ?
handle.write.assert_any_call(). handle.write.call_args_listSipariş önemliyse her aramayı almak için de kullanabilirsiniz .
m.return_value.write.assert_called_once_with('some stuff')daha iyi imo. Çağrı kaydetmekten kaçınır.
Mock.call_args_listetmek Mock.assert_xxx, yöntemlerden herhangi birini çağırmaktan daha güvenlidir . Eğer Mock'un nitelikleri olan ikincisini yanlış hecelerseniz, her zaman sessizce geçerler.
Basit bir dosya için mock_open kullanmak için read()( bu sayfada zaten verilen orijinal mock_open snippet'i daha çok yazmaya yöneliktir):
my_text = "some text to return when read() is called on the file object"
mocked_open_function = mock.mock_open(read_data=my_text)
with mock.patch("__builtin__.open", mocked_open_function):
with open("any_string") as f:
print f.read()
Not: mock_open için dokümanlara göre, bu özellikle içindir read(), bu nedenle for line in förneğin ortak kalıplarla çalışmaz .
Python 2.6.6 / alay 1.0.1 kullanır
for line in opened_file:kod türüyle çalışmak için alamıyorum . Ben uygular tekrarlanabilir StringIO ile denemeye çalıştı __iter__ve bunun yerine my_text, ama şans yok kullanarak .
read()sizin for line in opened_filedurumunuz için çalışmaz ;
for line in f:desteği bunun yerine bir StringIO nesnesiopen() olarak dönüş değeri alay edilerek elde edilebilir .
with open("any_string") as f: print f.read()
En iyi cevap faydalı ama biraz daha genişledim.
Dosya nesnenizin ( fin as f) değerini, iletilen bağımsız değişkenlere dayanarak ayarlamak istiyorsanız open(), bunu yapmanın bir yolu vardır:
def save_arg_return_data(*args, **kwargs):
mm = MagicMock(spec=file)
mm.__enter__.return_value = do_something_with_data(*args, **kwargs)
return mm
m = MagicMock()
m.side_effect = save_arg_return_array_of_data
# if your open() call is in the file mymodule.animals
# use mymodule.animals as name_of_called_file
open_name = '%s.open' % name_of_called_file
with patch(open_name, m, create=True):
#do testing here
Temel olarak, open()bir nesneyi döndürür ve o nesneyi withçağırır __enter__().
Düzgün alay open()etmek için, sahte bir nesne döndürmek için alay etmeliyiz . Bu sahte nesne, daha sonra istediğimiz sahte veri / dosya nesnesini (dolayısıyla ) döndürmek için __enter__()çağrıyı alay etmelidir ( MagicMockbunu bizim için yapar mm.__enter__.return_value). Bunu yukarıdaki şekilde 2 alayla yapmak, geçirilen argümanları yakalamamızı ve yöntemimize open()aktarmamızı sağlar do_something_with_data.
Bir dize olarak tüm sahte bir dosyayı geçti open()ve benim do_something_with_datagibi görünüyordu:
def do_something_with_data(*args, **kwargs):
return args[0].split("\n")
Bu, dizeyi bir listeye dönüştürür, böylece normal bir dosyada yaptığınız gibi aşağıdakileri yapabilirsiniz:
for line in file:
#do action
__enter__? Kesinlikle önerilen bir yol daha bir kesmek gibi görünüyor.
Oyuna biraz geç kalmış olabilirim, ancak openyeni bir dosya oluşturmak zorunda kalmadan başka bir modülü çağırırken bu benim için çalıştı .
test.py
import unittest
from mock import Mock, patch, mock_open
from MyObj import MyObj
class TestObj(unittest.TestCase):
open_ = mock_open()
with patch.object(__builtin__, "open", open_):
ref = MyObj()
ref.save("myfile.txt")
assert open_.call_args_list == [call("myfile.txt", "wb")]
MyObj.py
class MyObj(object):
def save(self, filename):
with open(filename, "wb") as f:
f.write("sample text")
Modülün openiçindeki işlevi yamaya ekleyerek, bir dosya oluşturmadan bir dosyaya yazabilirim.__builtin__mock_open()
Not: cython kullanan bir modül kullanıyorsanız veya programınız herhangi bir şekilde cython'a bağlıysa, dosyanızın üstüne dahil ederek cython __builtin__modülünü içe aktarmanız gerekir import __builtin__. Eğer __builtin__cython kullanıyorsanız evrensel alay ile alay edemezsiniz .
import __builtin__Test modülüme eklediğimden emin olmalıydım. Bu makale, bu tekniğin neden iyi çalıştığını açıklığa kavuşturmaya yardımcı oldu: ichimonji10.name/blog/6
Bu, bir düzeltme ekinin bir json yapılandırmasını okuması için çalıştı.
class ObjectUnderTest:
def __init__(self, filename: str):
with open(filename, 'r') as f:
dict_content = json.load(f)
Alaycı nesne, open () işlevi tarafından döndürülen io.TextIOWrapper nesnesidir
@patch("<src.where.object.is.used>.open",
return_value=io.TextIOWrapper(io.BufferedReader(io.BytesIO(b'{"test_key": "test_value"}'))))
def test_object_function_under_test(self, mocker):
Daha fazla dosyaya ihtiyacınız yoksa test yöntemini dekore edebilirsiniz:
@patch('builtins.open', mock_open(read_data="data"))
def test_testme():
result = testeme()
assert result == "data"