Wie kann ich ein offenes Mal in einer mit Aussage (mit dem Mock-Framework in Python) verspotten?

Wie teste ich den folgenden Code mit Spott (mit Spott, der Patch-Dekorator und Sentinels von Michael Foord's Mock Framework zur Verfügung gestellt ):

def testme(filepath): with open(filepath, 'r') as f: return f.read() 

7 Solutions collect form web for “Wie kann ich ein offenes Mal in einer mit Aussage (mit dem Mock-Framework in Python) verspotten?”

Der Weg, dies zu tun hat sich in mock 0.7.0, die schließlich unterstützt Spott der Python-Protokoll Methoden (magische Methoden), vor allem mit dem MagicMock:

http://www.voidspace.org.uk/python/mock/magicmock.html

Ein Beispiel für das Verspotten als Kontextmanager (von der Beispielseite in der Mock-Dokumentation):

 >>> 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') 

Mit den neuesten Versionen von Mock, können Sie die wirklich nützliche mock_open Helfer verwenden:

Mock_open (mock = Keine, read_data = Keine)

Eine Helferfunktion, um einen Spott zu schaffen, um die Verwendung von offen zu ersetzen. Es funktioniert für Open direkt genannt oder als Kontext Manager verwendet.

Das Mock-Argument ist das Mock-Objekt zu konfigurieren. Wenn keine (die Voreinstellung), dann wird ein MagicMock für Sie erstellt, wobei die API auf Methoden oder Attribute beschränkt ist, die auf Standard-Datei-Handles verfügbar sind.

Read_data ist eine Zeichenfolge für die Lesemethode des Dateizugriffs, um zurückzukehren. Dies ist standardmäßig eine leere Zeichenfolge.

 >>> 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') 

Es gibt viel Lärm in diesen Antworten; Fast alle sind richtig aber veraltet und nicht ordentlich. mock_open ist Teil von mock Framework und ist sehr einfach zu bedienen. patch der als Kontext verwendet wird, gibt das Objekt zurück, das verwendet wird, um das gepatchte zu ersetzen: Sie können es verwenden, um Ihren Test einfacher zu machen.

Python 3.x

Verwenden Sie builtins anstelle von __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") 

Python 2.7

mock ist nicht Teil von unittest und Sie sollten Patch __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") 

Dekoratorkasten

Wenn du patch als Dekorateur mit mock_open() 's Ergebnis verwenden würde, da das Argument des new patch ein bisschen komisch sein kann.

In diesem Fall ist es besser, das Argument des new_callable patch zu verwenden und daran zu erinnern, dass alle zusätzlichen Argumente, die patch nicht verwendet, an new_callable Funktion übergeben werden, wie in new_callable beschrieben.

Patch () nimmt beliebige Keyword-Argumente. Diese werden an den Mock (oder new_callable) über den Bau weitergegeben.

Zum Beispiel dekorierte Version für Python 3.x ist:

 @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") 

Denken Sie daran, dass in diesem Fall patch wird das Mock-Objekt als Argument von Ihnen Test-Funktion hinzufügen.

Aktualisiert Daryls Antwort, um Änderungen an der Mock-Klasse zu beheben.

 @patch('__builtin__.open') def test_testme(self, open_mock): # # setup # context_manager_mock = Mock() open_mock.return_value = context_manager_mock file_mock = Mock() file_mock.read.return_value = sentinel.file_contents enter_mock = Mock() enter_mock.return_value = file_mock exit_mock = Mock() setattr( context_manager_mock, '__enter__', enter_mock ) setattr( context_manager_mock, '__exit__', exit_mock ) # # exercise # result = cbot.testme(sentinel.filepath) # # verify # self.assertEquals(result, sentinel.file_contents) self.assertEquals(open_mock.call_args, ((sentinel.filepath, 'r'), {})) self.assertEquals(context_manager_mock.method_calls, [('__enter__', (), {}), ('__exit__', (None, None, None), {})]) self.assertEquals(file_mock.method_calls, [('read', (), {})]) 

Zur Verwendung von mock_open für eine einfache Datei read() (das Original mock_open Snippet bereits auf dieser Seite gegeben ist mehr für schreiben):

 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() 

Hinweis wie pro docs für mock_open, das ist speziell für read() , also funktioniert nicht mit gängigen mustern wie for line in f , zum Beispiel.

Verwendet python 2.6.6 / mock 1.0.1

Ich könnte ein bisschen spät zum Spiel sein, aber das hat für mich gearbeitet, wenn man in einem anderen Modul aufruft, ohne eine neue Datei erstellen zu müssen.

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") 

Durch das __builtin__ der open Funktion innerhalb des __builtin__ Moduls zu meinem mock_open() kann ich das Schreiben in eine Datei mock_open() , ohne eine zu erstellen.

Hinweis: Wenn Sie ein Modul verwenden, das Cython verwendet oder Ihr Programm von Zython in irgendeiner Weise abhängt, müssen Sie __builtin__ Modul import __builtin__ den import __builtin__ am Anfang Ihrer Datei import __builtin__ . Sie werden nicht in der Lage sein, die universelle __builtin__ zu verspotten, wenn Sie Cython verwenden.

Die Top-Antwort ist nützlich, aber ich habe es ein bisschen erweitert.

Wenn du den Wert deines Dateiobjekts (das f in as f ) auf der Basis der Argumente, die an open() werden soll, ist, ist es eine Möglichkeit, es zu tun:

 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 

Grundsätzlich wird open() ein Objekt zurückgeben und with __enter__() auf dieses Objekt aufrufen.

Um richtig zu verspotten, müssen wir aufschieben open() , um ein Scheinobjekt zurückzugeben. Dieses Mock-Objekt sollte dann den __enter__() MagicMock ( MagicMock wird das für uns tun), um das Mock-Daten- / Datei-Objekt zurückzugeben, das wir wollen (also mm.__enter__.return_value ). do_something_with_data dies mit 2 do_something_with_data , erlaubt uns die oben genannte Möglichkeit, die an open() Argumente zu erfassen und sie an unsere do_something_with_data Methode do_something_with_data .

Ich habe eine ganze Mock-Datei als String do_something_with_data um zu open() und meine do_something_with_data sah so aus:

 def do_something_with_data(*args, **kwargs): return args[0].split("\n") 

Dies verwandelt die Zeichenfolge in eine Liste, so können Sie die folgenden wie Sie mit einer normalen Datei:

 for line in file: #do action 
  • Wie man eine Funktion, die in einem separaten Python-Modul mit mock's @ patch definiert ist, verspottet
  • Verwenden Sie mock Patch, um eine Instanzmethode zu verspotten
  • Python mock - patching eine Methode ohne behindert Umsetzung
  • Wie kann ich Anruf-Argumente überprüfen, wenn sie sich mit unittest.mock ändern werden
  • Python ist die beste Programmiersprache der Welt.