Używam Mocka (który jest teraz unittest.mock na py3.3 +) do tego:
from mock import patch
from PyQt4 import Qt
@patch.object(Qt.QMessageBox, 'aboutQt')
def testShowAboutQt(self, mock):
self.win.actionAboutQt.trigger()
self.assertTrue(mock.called)
W twoim przypadku może to wyglądać tak:
import mock
from mock import patch
def testClearWasCalled(self):
aw = aps.Request("nv1")
with patch.object(aw, 'Clear') as mock:
aw2 = aps.Request("nv2", aw)
mock.assert_called_with(42)
Mock obsługuje wiele przydatnych funkcji, w tym sposoby łatania obiektu lub modułu, a także sprawdzanie, czy została wywołana właściwa rzecz itp.
Caveat emptor! (Kupujący, strzeż się!)
Jeśli błędnie wpiszesz assert_called_with
(do assert_called_once
lub assert_called_wiht
), twój test może nadal działać, ponieważ Mock pomyśli, że jest to wyszydzona funkcja i z radością pójdzie dalej, chyba że użyjesz autospec=true
. Aby uzyskać więcej informacji, przeczytaj assert_called_once: Threat or Menace .
Tak, jeśli używasz Pythona 3.3+. Możesz użyć wbudowanej
unittest.mock
metody assert o nazwie. W przypadku Pythona 2.6+ użyj cofania wstecznegoMock
, co jest tym samym.Oto krótki przykład w Twoim przypadku:
from unittest.mock import MagicMock aw = aps.Request("nv1") aw.Clear = MagicMock() aw2 = aps.Request("nv2", aw) assert aw.Clear.called
źródło
Nie jestem świadomy niczego wbudowanego. Wdrożenie jest dość proste:
class assertMethodIsCalled(object): def __init__(self, obj, method): self.obj = obj self.method = method def called(self, *args, **kwargs): self.method_called = True self.orig_method(*args, **kwargs) def __enter__(self): self.orig_method = getattr(self.obj, self.method) setattr(self.obj, self.method, self.called) self.method_called = False def __exit__(self, exc_type, exc_value, traceback): assert getattr(self.obj, self.method) == self.called, "method %s was modified during assertMethodIsCalled" % self.method setattr(self.obj, self.method, self.orig_method) # If an exception was thrown within the block, we've already failed. if traceback is None: assert self.method_called, "method %s of %s was not called" % (self.method, self.obj) class test(object): def a(self): print "test" def b(self): self.a() obj = test() with assertMethodIsCalled(obj, "a"): obj.b()
Wymaga to, aby sam obiekt nie modyfikował self.b, co prawie zawsze jest prawdą.
źródło
Tak, mogę podać zarys, ale mój Python jest trochę zardzewiały i jestem zbyt zajęty, aby szczegółowo wyjaśniać.
Zasadniczo musisz umieścić proxy w metodzie, która wywoła oryginał, np:
class fred(object): def blog(self): print "We Blog" class methCallLogger(object): def __init__(self, meth): self.meth = meth def __call__(self, code=None): self.meth() # would also log the fact that it invoked the method #example f = fred() f.blog = methCallLogger(f.blog)
Ta odpowiedź StackOverflow na temat połączeń wywoływanych może pomóc ci zrozumieć powyższe.
Bardziej szczegółowo:
Chociaż odpowiedź została przyjęta, ze względu na ciekawą dyskusję z Glennem i kilka wolnych minut, chciałem rozszerzyć moją odpowiedź:
# helper class defined elsewhere class methCallLogger(object): def __init__(self, meth): self.meth = meth self.was_called = False def __call__(self, code=None): self.meth() self.was_called = True #example class fred(object): def blog(self): print "We Blog" f = fred() g = fred() f.blog = methCallLogger(f.blog) g.blog = methCallLogger(g.blog) f.blog() assert(f.blog.was_called) assert(not g.blog.was_called)
źródło
Możesz wyszydzać
aw.Clear
, ręcznie lub używając frameworka testowego, takiego jak pymox . Ręcznie zrobiłbyś to za pomocą czegoś takiego:class MyTest(TestCase): def testClear(): old_clear = aw.Clear clear_calls = 0 aw.Clear = lambda: clear_calls += 1 aps.Request('nv2', aw) assert clear_calls == 1 aw.Clear = old_clear
Używając pymox, zrobiłbyś to w ten sposób:
class MyTest(mox.MoxTestBase): def testClear(): aw = self.m.CreateMock(aps.Request) aw.Clear() self.mox.ReplayAll() aps.Request('nv2', aw)
źródło