简体   繁体   中英

Specifying "any instance of class Foo" for mock assert_called_once_with()?

In assert_called_once_with , how can I specify a parameter is "any instance of class Foo"?

For example:

class Foo(): pass
def f(x): pass
def g(): f(Foo())
import __main__
from unittest import mock

mock.ANY of course passes:

with mock.patch.object(__main__, 'f') as mock_f:
  g()
  mock_f.assert_called_once_with(mock.ANY)

and of course, another instance of Foo doesn't pass.

with mock.patch.object(__main__, 'f') as mock_f:
  g()
  mock_f.assert_called_once_with(Foo())

AssertionError: Expected call: f(<__main__.Foo object at 0x7fd38411d0b8>)
                  Actual call: f(<__main__.Foo object at 0x7fd384111f98>)

What can I put as my expected parameter such that any instance of Foo will make the assertion pass?

One simple solution is to do this in two steps:

with mock.patch.object(__main__, 'f') as mock_f:
    g()
    mock_f.assert_called_once()
    self.assertIsInstance(mock_f.mock_calls[0].args[0], Foo)

However, if you look at the implementation of ANY :

class _ANY(object):
    "A helper object that compares equal to everything."

    def __eq__(self, other):
        return True

    def __ne__(self, other):
        return False

    def __repr__(self):
        return '<ANY>'

ANY = _ANY()

you can see it's just an object that's equal to anything. So you could define your own equivalent that's equal to any instance of Foo :

class AnyFoo:
    "A helper object that compares equal to every instance of Foo."

    def __eq__(self, other):
        return isinstance(other, Foo)

    def __ne__(self, other):
        return not isinstance(other, Foo)

    def __repr__(self):
        return '<ANY Foo>'


ANY_FOO = AnyFoo()

Or more generically:

class AnyInstanceOf:
    "A helper object that compares equal to every instance of the specified class."

    def __init__(self, cls):
        self.cls = cls

    def __eq__(self, other):
        return isinstance(other, self.cls)

    def __ne__(self, other):
        return not isinstance(other, self.cls)

    def __repr__(self):
        return f"<ANY {self.cls.__name__}>"


ANY_FOO = AnyInstanceOf(Foo)

Either way, you can use it as you would ANY :

with mock.patch.object(__main__, 'f') as mock_f:
    g()
    mock_f.assert_called_once_with(ANY_FOO)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM