Make sure the method has been called in Python unit test

Suppose I have the following code in a Python unit test:

aw = aps.Request("nv1") aw2 = aps.Request("nv2", aw) 

Is there an easy way to claim that a particular method (in my case aw.Clear() ) was called during the second line of the test? for example there is something like this:

 #pseudocode: assertMethodIsCalled(aw.Clear, lambda: aps.Request("nv2", aw)) 
+57
python unit-testing
Sep 30 '10 at 10:32
source share
5 answers

I use Mock (which is now unittest.mock on py3. 3+) for this:

 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) 

For your case, it might look like this:

 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) # or mock.assert_called_once_with(42) 

Mock supports quite a few useful functions, including ways of fixing an object or module, as well as checking the correctness of a call, etc. Etc.

Let the buyer be vigilant! (Caution for buyer!)

If you are assert_called_with ( assert_called_once or assert_called_wiht ), your test can still be run since Mock will assume that it is assert_called_with assert_called_once and will be assert_called_wiht if you do not use autospec=true . For more information, read assert_called_once: Threat or Threat .

+103
Jan 19 '11 at 10:59
source share

Yes, if you are using Python 3. 3+. You can use the built-in unittest.mock for the unittest.mock method. For Python 2.6+ use the Mock sliding reverse port, which is the same.

Here is a quick example in your case:

 from unittest.mock import MagicMock aw = aps.Request("nv1") aw.Clear = MagicMock() aw2 = aps.Request("nv2", aw) assert aw.Clear.called 
+17
Aug 08 '16 at 16:13
source share

I do not know anything built in. This is pretty simple to implement:

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

This requires that the object itself does not modify self.b, which is almost always true.

+13
Sep 30 '10 at 10:49
source share

Yes, I can give you a diagram, but my Python is a little rusty, and I'm too busy to explain in detail.

Basically, you need to put the proxy in a method that will call the original, for example:

  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) 

This https://stackoverflow.com/a/4646266/ about the callee can help you understand the above.

More details:

Although the answer was accepted, due to an interesting discussion with Glenn and some free time, I wanted to increase my answer:

 # 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) 
+7
Sep 30 '10 at 10:46
source share

You can grease aw.Clear either manually or using a testing platform like pymox . Manually, you would do this using something like this:

 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 

Using pymox, you would do it like this:

 class MyTest(mox.MoxTestBase): def testClear(): aw = self.m.CreateMock(aps.Request) aw.Clear() self.mox.ReplayAll() aps.Request('nv2', aw) 
+4
Sep 30 '10 at 10:43
source share



All Articles