Doomsday
Doomsday

Reputation: 2668

How to test if instance's method is called with "self" when mocking?

I'm using unittest.mock, this wonderful library. However I was surprised by an unexpected behavior, and I don't see an obvious solution. I'm using it for my unit tests and it is vital to understand perfectly how it behaves to have useful tests.

I know the code below in show_bar is broken, it is calling a classmethod instead of the instance method. However, all my mock unittests are passing :

Code containing a bug:

class Foo(object):
    def bar(self):
        return "bar"

    def show_bar(self):
        return Foo.bar()

Expected usage:

foo = Foo()
assert foo.show_bar() == "bar"
# => throw exception: bar() missing 1 required positional argument: 'self'

Unittest tries unsuccessfully to catch this error with mock:

from unittest.mock import patch
with patch.object(Foo, 'bar', return_value="bar") as mock:
    foo = Foo()
    assert foo.show_bar() == "bar"
mock.assert_called_once()
# => no errors 

Ideally, I would like to assert that bar is called with self.bar() and NOT Foo.bar() ; which is wrong. Unfortunately, using mock.assert_called_with() does not take in account the self nor cls parameter, so I'm a bit confused.

EDIT: Trying to clarify. I'm looking for best practices to use the library unittest.mock when we need to patch an object's method. It seems not clear to me how to patch it, currently I have no way to assert if it's calling self.bar or Foo.bar.

Upvotes: 4

Views: 1955

Answers (1)

bruno desthuilliers
bruno desthuilliers

Reputation: 77912

I don't really understand why you'd need to mock the method to test that it does not raise a TypeError when called but anyway... Someone else might explain how to solve this using unittest.mock, in the meantime you can just skip unittest.mock and mock Foo.bar by yourself:

 callargs = dict()  
 def mock_bar(self):
     callargs["self"] = self
     return "bar"

 foobar = Foo.__dict__["bar"] 
 Foo.bar = mock_bar
 try: 
     foo = Foo()
     assert foo.show_bar() == "bar"
     assert "self" in callargs
     assert callargs["self"] is foo
 finally:
     Foo.bar = foobar

Upvotes: 1

Related Questions