How to patch an object's attributes with `side_effect` - python

So I have a file some_class.py with:
class SomeReader:
def read_path(self, url):
return "read_path"
class SomeClass:
def __init__(self, url):
self.reader = SomeReader(url)
print(self.reader.read_path(""))
And a test file some_class_test.py:
from some_class import SomeClass, SomeReader
#patch("some_class.SomeReader")
def test_some_class(mock_some_reader):
def mock_read_path(url):
return "mock_read_path"
mock_some_reader.read_path.side_effect = mock_read_path
SomeClass("")
I'm expecting that when I run this test, it will print mock_read_path but instead it prints <MagicMock name='SomeReader().read_path()' id='140701381288480'>. How do I fix this? I want to mock both the class initialization of SomeReader, hence I use #patch("some_class.SomeReader"). But I also want to mock the read_path function of SomeReader, hence I have mock_some_reader.read_path.side_effect = mock_read_path but that doesn't seem to work.

What you're doing is making a mock of the class itself, not the instances of the classes. The mock replaces call to instantiate SomeReader(url) (basically replacing the __init__ method of the class).
What you want to do is then mock the return value of the fake instance being created by SomeReader(url)
#patch("some_class.SomeReader")
def test_some_class(mock_some_reader):
def mock_read_path(url):
return "mock_read_path"
mock_some_reader.return_value.read_path.side_effect = mock_read_path
SomeClass("")

Related

Python - Class object as function argument: Object only - Class not in argument

I am trying to write a function taking a string as an argument and using this argument as a class object.
Note that my explanantion might be strangely formulated sice I could not find an answer online. The MWE below should clarify what I mean, the problematic line is indicated.
Edit: in the MWE, "print" is an example. I need to be able to call the object to update it, print it or, in the case of a list, append to it. I need access to the object itself, not the value of the object.
MWE
# Create a class
class myClass():
def __init__(self):
self.one = "Test"
self.two = "Plop"
# Define function
def myFunction (parameter):
print(myObject.parameter)##### This line is currently not possible.
# Use class
myObject = myClass()
# Use function
myFunction("one")
I am not trying to append a new object to the class, only to call an existing object.
Is this even possible?
Looks like you need the built-in function called getattr
my_object = myClass()
def my_function(parameter):
print(getattr(my_object, parameter, None))
also this is not the best practice to call objects from outer scope like that. i'd suggest to use dict magic methods:
class MyClass:
def __init__(self):
self.one = "Test"
self.two = "Plop"
def __getitem__(self, parameter):
return getattr(self, parameter, None)
def __setitem__(self, parameter, value):
return setattr(self, parameter, value)
my_obj = MyClass()
parameter = "x"
print(my_obj[parameter])
my_obj[parameter] = "test"
print(my_obj.x)
You need to use getarttr():
# Create a class
class myClass():
def __init__(self):
self.one = "Test"
self.two = "Plop"
# Use class
myObject = myClass()
# Define function
def myFunction(parameter):
print(getattr(myObject, parameter))##### This line is currently possible.
# Use function
myFunction("one")

How to mock nested method call in Python

I am quite new to Python. I have OpenshiftApiController class and a test class TestOpenshiftApiController. I am using python unittest library for Testing.
(1) In setUp() method of test class I am creating one object of OpenshiftApiController class and that class have below line in constructor. I want to mock DynamicClient(base_kube_client) which is present in __init__() of the actual class.
self.dynamic_client = DynamicClient(base_kube_client)
(2) Also in test_create_object() of Test class, I am calling create_object() of OpenshiftApiController class and there I want to mock nested method resource_client.create(**create_args) which is present in create_object() of actual class.
return_obj = resource_client.create(**create_args)
Actual Class to be tested:
class OpenshiftApiController:
def __init__(self, base_kube_client, default_namespace=DEFAULT_NAMESPACE):
self.base_kube_client = base_kube_client
self.dynamic_client = DynamicClient(base_kube_client)
self.default_namespace = default_namespace
def create_object(self, object_config, default_namespace=None, driver_request_id=None):
resource_client = self.__get_resource_client()
create_args = self.__build_create_arguments(resource_client, object_config, default_namespace)
return_obj = resource_client.create(**create_args)
return return_obj
Test Class:
class TestOpenshiftApiController(unittest.TestCase):
def setUp(self):
self.base_kube_client = client.ApiClient()
self.api_ctl = OpenshiftApiController(self.base_kube_client, default_namespace='default')
def test_create_object(self):
object_config = ObjectConfiguration()
self.api_ctl.create_object(object_config)
How to mock those 2 things? Any help is highly appreciable.

python #patch custom patched object not updating

I want to patch a function(func_to_be_mocked ) returning class object (ReturnValue) with my own mocked version (ReturnValueMock). The function I want to test(func_to_be_tested) is setting some values on the object. But my mocked object is not getting updated and showing the deafult values. (i.e. assert statement in test is failing). What am I missing?
to_test.py
class ReturnValue():
def __init__(self):
self.a = ""
class ToTest():
def func_to_be_mocked(self):
return ReturnValue()
def func_to_be_tested(self):
ret_val = self.func_to_be_mocked()
ret_val.a = "set"
test.py
from mock import patch
import unittest
from .to_test import ToTest
class ReturnValueMock():
def __init__(self):
self.a = ""
class Tests(unittest.TestCase):
def setUp(self):
self.ret_val = ReturnValueMock()
#patch("to_test.ToTest.func_to_be_mocked")
def test(self, mocked_func):
mocked_func.return_val = self.ret_val
ToTest().func_to_be_tested()
assert self.ret_val == "set"
Thing tried so far
Added print statements to verify that the object in function under test is same as the one I am providing as mock (Object hash code code are same)

mocking an instance method of inner object in python 3.4

I have a class in my code that makes use of a third party library. I would like to mock the instance method of the object that I obtain by calling an instance method of the library class. I am not clear on how to mock the instance method of this inner object. Following is my code:
My class:
from a import A
class MyClass(object):
def __init__(self):
self.obj = A()
def do_something(self):
b = self.obj.get_inner_object()
result = b.do_inner()
return result
Here is my test class:
from unittest import TestCase
from unittest.mock import MagicMock
from unittest.mock import patch
from a import A
class TestMyClass(TestCase):
def __init__(self):
self.my_class = MyClass()
#patch.object(A,'get_inner_object')
def test_do_something(self, mock_get_inner_object):
test_res = self.my_class.do_something()
As you can see above, I would like to mock away 2 methods of my library - get_inner_object() and do_inner() which is the instance method of the object returned by get_inner_object(). I was able to mock get_inner_object(), but I am not clear on how to mock the do_inner() method. Please clarify. Here's the help I am following: https://www.toptal.com/python/an-introduction-to-mocking-in-python
Just mock out all of A:
#patch('a.A')
def test_do_something(self, mock_A):
mock_b = mock_A.return_value.get_inner_object.return_value
mock_b.do_inner.return_value = 'mocked return value'
test_res = self.my_class.do_something()
self.assertEqual(test_res, 'mocked return value')
After all, you are testing MyClass here, not A.
Either way, wether you use #patch.object(A, 'get_inner_object') or patch all of A, the self.obj.get_inner_object() expression calls a Mock instance, so the .return_value attribute is returned at that point. The do_inner method is just another chained call on that returned mock here, so you can set what is returned for that method by setting the .return_value attribute to something you test for.
To translate that back to your #patch.object() situation, mock_b is then the mock_inner_object.return_value object:
#patch.object(A,'get_inner_object')
def test_do_something(self, mock_get_inner_object):
mock_b = mock_get_inner_object.return_value
mock_b.do_inner.return_value = 'mocked return value'
test_res = self.my_class.do_something()
self.assertEqual(test_res, 'mocked return value')

Assert that derived class methods are called in correct order

I'm trying to verify that the implementation of Base.run_this calls the methods of derived class (derived_method_[1st|2nd|3rd]) in correct order. As the output shows, the test is not working. How can I fix this?
class Base(object):
__metaclass__ = abc.ABCMeta
def __init__(self, parameters):
self.parameters = parameters;
#abc.abstractmethod
def must_implement_this(self):
return
def run_this(self):
self.must_implement_this()
if(self.parameters):
first = getattr(self, "derived_method_1st")
first()
second = getattr(self, "derived_method_2nd")
second()
third = getattr(self, "derived_method_3rd")
third()
class Derived(Base):
def must_implement_this(self):
pass
def derived_method_1st(self):
pass
def derived_method_2nd(self):
pass
def derived_method_3rd(self):
pass
mocked = MagicMock(wraps=Derived(True))
mocked.run_this()
mocked.assert_has_calls([call.derived_method_1st(), call.derived_method_2nd(), call.derived_method_3rd()])
Output
AssertionError: Calls not found.
Expected: [call.derived_method_1st(), call.derived_method_2nd(), call.derived_method_3rd()]
Actual: [call.run_this()]
wraps doesn't work well with instances. What happens here is that mocked.run_this returns a new mock object that 'wraps' Derived(True).run_this, where the latter is a bound method to the original Derived() instance.
As such, that method will call self.derived_method_* methods that are bound to that original instance, not to the mock.
You could patch in the run_this method on a spec mock instead:
mock = MagicMock(spec=Derived)
instance = mock()
instance.run_this = Derived.run_this.__get__(instance) # bind to mock instead
instance.parameters = True # adjust as needed for the test
instance.run_this()
Demo:
>>> mock = MagicMock(spec=Derived)
>>> instance = mock()
>>> instance.run_this = Derived.run_this.__get__(instance) # bind to mock instead
>>> instance.parameters = True # adjust as needed for the test
>>> instance.run_this()
>>> instance.mock_calls
[call.must_implement_this(),
call.derived_method_1st(),
call.derived_method_2nd(),
call.derived_method_3rd()]

Categories

Resources