Python, can't assert if method called from another class - python

I have the following code in Python:
class A():
def doSomething(self, bClass):
print(bClass.theThing)
class B():
def __init__(self, theThing):
self.theThing = theThing
def foo():
a = A()
b = B("that thing")
a.doSomething(b)
I have those classes and the function foo() stored in testing.py and I want to test that the A's method was called with:
import testing, unittest
from unittest.mock import patch
class TheTestClass(unittest.TestCase):
def test(self):
with patch('testing.A.doSomething') as do:
testing.foo()
do.assert_any_call()
But I always get 'doSomething() call not found'. I would be happier if I could understand why but at this point anything is welcome

After many hours I started figuring this out.
Like jwjhdev said assert_called_with() expects something and in my case a class but so does assert_any_call(). For some reason I was thinking assert_any_call() would just work but what I was thinking was assert_called() which just works without arguments. In the end I figured it out by adding a return b to the foo() function and:
def foo():
a = A()
b = B("that thing")
a.doSomething(b)
return b
class TheTestClass(unittest.TestCase):
def test(self):
with patch('testing.A.doSomething') as do:
b = testing.foo()
do.assert_any_call(b)

Related

How can I call an arbitrary interface method on a concrete instance in python?

Lets say I have an interface with a couple abstract methods
class SomeInterface(ABC):
#abstractmethod
def foo(self):
"""Does something i want all implementers to do"""
#abstractmethod
def bar(self):
"""Does something i want all implementers to do"""
And a couple implementations
class A(SomeInterface):
def foo(self):
print("A does foo like this")
def bar(self):
print("A does bar like this")
class B(SomeInterface):
def foo(self):
print("B does foo like this")
def bar(self):
print("B does bar like this")
With that set up, I'm in a situation where i want to have a function that can run some interface function that i specify on some implementations of that interface. So, the function can take as parameters some form of reference to either foo or bar, and then run that on some instances of A and B that it creates. Something like this:
def run_any_interface_method(func: Callable):
a = A()
a.func()
b = B()
b.func()
run_any_interface_method(SomeInterface.foo)
But this wont work of course. What should be the best solution? I may have many possible implementations of SomeInterface and many interface functions. I considered this solution:
def run_any_interface_method(func: Callable):
a = A()
func(a)
b = B()
func(b)
run_any_interface_method(SomeInterface.foo)
Which passes the instance, either Aor B, as the argument self, but func in this case is still the unimplemented abstractmethod, so it does nothing (interestingly, it does not complain when doing so). I considered iterating through the names of the methods to find the right one, but that seems kludgy. Is there a better way?
Edit
The solution i went with is:
from operator import methodcaller
def run_any_interface_method(func: Callable):
func = methodcaller(func.__name__)
a = A()
func(a)
b = B()
func(b)
run_any_interface_method(SomeInterface.foo)
Let func be an instance of operator.methodcaller.
from operator import methodcaller
def run_any_interface_method(func):
a = A()
func(a)
b = B()
func(b)
# Run a.foo() and b.foo()
run_any_interace_method(methodcaller('foo'))
# Run a.bar() and b.bar()
run_any_interace_method(methodcaller('bar'))
You can also take a string as an argument instead and construct the methodcaller instance inside the function.
def run_any_interface_method(method_name):
func = methodcaller(method_name)
a = A()
func(a)
b = B()
func(b)
# Run a.foo() and b.foo()
run_any_interace_method('foo')
# Run a.bar() and b.bar()
run_any_interace_method('bar')

How to mock a method inside another method with Python unittest?

I am struggling to mock a method inside another method i.e Let's say I have 2 classes A, B as follows:
class A:
def method_A(self):
return "Hi"
class B:
def method_B(self):
instance_A = A()
result = instance_A.method_A()
print(result)
Here I want to mock method_A while testing method_B but can't find a way. Thanks in advance
I hope this is what you are looking for.
class A:
def method_A(self):
return "Hi"
class B:
def method_B(self):
instance_A = A()
result = instance_A.method_A()
return result
import mock
def mock_A(self):
return 'Bye'
def test_method_B():
with mock.patch.object(A, 'method_A', new=mock_A):
result = B().method_B()
assert result == 'Bye'
What exactly do you mean by mocking a method?
If you mean why your code isn't doing anything that's because you need to call the method
afterwards:-
B.method_B()
Maybe that helps somehow, if not could you explain the problem a lil'bit more.
Well in that case first you wanna import mock library by simply typing import mock
then you wanna create a function for
1) Mocking
def mocking_method_A(self):
return Some_value
2)Testing
def testing_method_B():
with mock.patch.object(A, 'method_A', new=mocking_A):
result = B().method_B()
assert result == Some_value

How does one use pytest monkeypatch to patch a class

I would like to use [pytest monkeypatch][1] to mock a class which is imported
into a separate module. Is this actually possible, and if so how does one do it? It seems like I have not seen an example for this exact situation. Suppose you have app with and imported class A in something.py
from something import A #Class is imported
class B :
def __init__(self) :
self.instance = A() #class instance is created
def f(self, value) :
return self.instance.g(value)
inside my test.py I want to mock A inside B
from something import B
#this is where I would mock A such that
def mock_A :
def g(self, value) :
return 2*value
#Then I would call B
c = B()
print(c.g(2)) #would be 4
I see how monkeypatch can be used to patch instances of classes, but how is it done for classes that have not yet been instantiated? Is it possible? Thanks!
[1]: https://docs.pytest.org/en/latest/monkeypatch.html
tested this, works for me:
def test_thing(monkeypatch):
def patched_g(self, value):
return value * 2
monkeypatch.setattr(A, 'g', patched_g)
b = B()
assert b.f(2) == 4

How to mock a method of an imported instance

I am writing unit test for some python modules. However, I cannot work out a way to mock a method of an imported instance. Below is the python modules that I want to test.
--bar.py--
class A():
#classmethod
def method_1(self):
...
a = A()
--foo.py--
from bar import a
class B():
#classmethod
def b(cls):
if a.method_1():
return True
else:
return False
--test_foo.py--
from foo import B
class TestB(TestCase):
#patch('foo.a.method_1')
def test_b(self, mock_method_1):
mock_method_1.return_value = True
test_b = B.b()
...
This does not work. My test case is still calling original method_1 instead of the one I mocked.
Use the patch.object decorator instead. It patches an object's attributes instead of patching a global method.
If that doesn't work, try patching bar.a instead of foo.a, but I don't think that's your problem here.
Update
The question changed to a class method, so I think this will work:
--test_foo.py--
from foo import B
class TestB(TestCase):
#patch('bar.A.method_1')
def test_b(self, mock_method_1):
mock_method_1.return_value = True
test_b = B.b()
...

Can Monkey patching replace existing function definition in a class?

I know how fierce the SO community is so I'll try my best to keep the question minimal, complete and verifiable.
What I simply want to know is can monkey patching be used to replace the definition of an existing function?
for example:
class A():
def foo():
print '2'
def foo():
print '5'
A.foo = foo
This way doesn't seem to work also as to why I don't just add a new function instead of replacing an existing one, I call these functions in other classes and it is my understanding that monkey patching adds those functions at run-time and I need my python code to run on an Apache spark server which throws an error deeming the calls to that function unreferenced.
So please be nice and help me out or suggest a work around.
Thanks.
Edit: The goal of the code is to print 5 when A.foo is called.
Your only problem is that you aren't defining foo correctly in the first place. It needs to take an explicit argument for the instance calling it.
class A(object):
def __init__(self)
self.x = 2
def foo(self):
print(self.x)
def foo(this):
print(this.x + 3)
A.foo = foo
a = A()
a.foo() # outputs 5 in Python 2 and Python 3
In a very real sense, monkey patching is how classes are created in the first place. A class statement is almost just syntactic sugar for the following code:
def foo(self):
print(self.x)
A = type('A', (object,), {'foo': foo})
del foo
It's not too much of a simplification to image the definition of type being something like
def type(name, bases, d):
new_class = magic_function_to_make_a_class()
new_class.name = name
new_class.bases = bases
for k, v in d.items():
setattr(new_class, k, v)
return new_class
I hope I understand what you are trying to do here. This would work in Python 3:
class A():
def foo():
print('2')
def foo():
A.foo = lambda: print('5')
A.foo() # Print '2'
foo() # Assign the new method
A.foo() # Prints '5'
In Python 2 however there are several caveats.
print is not a method as it is in Python 3 (see here: Why doesn't print work in a lambda?)
You can't just call unbound messages (see here: In Python, can you call an instance method of class A, but pass in an instance of class B?)
So you have to do it like this:
from __future__ import print_function
class A():
def foo():
print('2')
def foo():
A.foo = lambda: print('5')
A.foo.__func__() # Print '2'
foo() # Assign the new method
A.foo.__func__() # Prints '5'
Edit:
After seeing your question in the comment I think you actually want something different. Which is this:
class A():
def foo(self):
print '2'
def foo(self):
print '5'
a = A()
a.foo() # Print '2'
A.foo = foo # Assign the new method
a.foo() # Prints '5'
This works just fine in Python 2.
The self is a reference to the current instance the method is bound to. It is not used when you just call something like print which access any properties or methods attached to that instance. But for a different case please have a look at the following example:
class A():
msg = "Some message"
def foo(self):
print self.msg
def bar(self):
self.msg = "Some other message"
a = A()
a.foo() # Print old msg
A.bar = bar # Assign the new method
a.bar() # Assigns new message
a.foo() # Prints new message
Also as chepner points out in a comment under his post:
The name self isn't special; it's just a convention. You could use
this if you really wanted to, and it doesn't need to be the same name
in both functions defined here. What is important is that the first
argument to a function used as an instance method will be a reference
to the calling object. a.foo() is almost exactly the same as A.foo(a)

Categories

Resources