Monkey patch an object from another module in Python - python

I've a class, say foo, in module 1.
class foo():
def __init__(var1, var2):
self.var1 = var1
self.var2 = var2
def method1(self):
pass
def method2(self):
pass
foo_ = foo("blah", "blah")
The foo_ object is widely used in various modules across the code base. I've to write a test for a method in module 2 which uses the foo_ object.
Module 2:
from module1 import foo_
import module3
def blah():
foo_.method1()
module3.random_method()
return blah
The random_method in module 3 also imports and calls another method of foo_. I've a dummy foo_ object in my test module.The test is for the blah method. Here's what I've so far.
Test Module:
from module1 import foo
from module2 import blah
#pytest.fixture()
def dummy_foo_():
var1 = 'blah'
var2 = 'blah'
return foo(var1,var2)
def test_blah(dummy_foo_):
assert blah() == 'blah'
Is there a way I can get the test_blah to work where the blah method would use the dummy foo_ object instead of the one imported in the module 1?

You can use mock.patch to temporarily patch module1.foo_ with dummy_foo_ by using it as a context manager
from mock import patch
def test_blah(dummy_foo_):
with patch('module1.foo_', dummy_foo_) as mock:
assert blah() == 'blah'

Related

unittest mock how to mock a method being called

I want to test that method a calls method b. These methods are in separate files, and are not a part of class object.
# file_a.py
from file_b import b
def a():
b()
# file_b.py
def b():
test
import unittest
from unittest import mock
from file_a import a
class MyTestCase(unittest.TestCase):
#mock.patch('file_b.b')
def test_b_called(self, mock):
a()
mock.assert_called()
if __name__ == "__main__":
unittest.main()
This fails with AssertionError: Expected 'b' to have been called.
Is there a right way to do this?
When you import a function into the current namespace, like in your example, the function will need to be patched in that namespace. In your case, you need:
#mock.patch('file_a.b')
You would patch file_b.b if you had done the import and use like this:
import file_b
def a():
file_b.b()

Python Class variable not keeping value

I declared a class with a class variable.
Module name my_moudle_1.py
For example:
class my_class:
my_dict={}#The class variable
def __init__(self):
return
In a different module - my_moudle_2.py i wrote:
from my_moudle_1 import my_class
Inside this module there is a class. In the class method i wrote:
my_class.my_dict['123']=5
In third module - my_moudle_3.py i wrote again:
from my_moudle_1 import my_class
When i am checking the my_dict variable value in the instance of my_class, i get
that the value is {}.
How can i update in a different module the class variable and use it
inside an instance in a different file?
Thanks
That shouldn't be the case. I can't reproduce this problem:
mymod.py
class my_class:
my_dict = {}
def __init__(self):
return
my_class.my_dict['foo'] = 'bar'
mymod2.py
from mymod import my_class
my_class.my_dict['greeting'] = 'Hello'
testapp.py
from mymod import my_class
import mymod2 # will modify my_dict as a side effect
my_class.my_dict['barq'] = 'foo'
print(my_class.my_dict)
$ python3 testapp.py
{'foo': 'bar', 'greeting': 'Hello', 'barq': 'foo'}
$

Monkey patching a class in a function that is called from a child method (Python)

Let's say I have this situation:
module2.py
class Bar:
def bar():
a = 5
# do stuff
Messages.show("Done")
module1.py
import module2
class Foo:
def __init__(self):
self.bar = module2.Bar()
def foo(self):
self.bar.bar()
I want to test the method Foo.foo(), but I want to ignore Messages.show("Done), ie I want calls to the Messages.show function to be done on a mock object. If foo was calling Messages.show directly, I could use monkeypatch on foo to mock the Messages class. But now, I'm calling a class from another module and I don't know how to specify that Messages.show calls should not be done ( the reason being that they access the Gui and that doesn't work in a test environment). Let's assume I cannot modify module2.py.
Just override what module2 thinks Messages is:
import module2
module2.Messages = ...

Scope of Python Class Variable?

Are class variables essentially global variables?
Consider this example, in bar.py:
class Bar(object):
b = {}
then in foo.py:
def foo1():
import bar
bar.Bar.b["key"] = "foo1"
def foo2():
import bar
print bar.Bar.b.get("key", "foo2")
foo1()
foo2()
The "key" value is persistently "foo1."
For my purposes this seems like a global variable. But why isn't the class variable being reset or deleted between the calls to foo1 and foo2?
It's a class attribute. In your case, the dict is bound to the class Bar. Everytime you import bar, you get the same class bar.Bar (after all, it is in the bar's global namespace), and consequentially, you get the same dict bar.Bar.b.
If you want each Bar instance to have a different dict, you need to make an instance:
class Bar(object):
def __init__(self):
self.b = {}
And then:
def foo1():
import bar
bar.Bar().b["key"] = "foo1"
def foo2():
import bar
print bar.Bar().b.get("key", "foo2")
foo1()
foo2()
As far as why the module bar isn't being garbage collected, when you import something, python stores a reference to that module (see sys.modules). The next time you import that module, python picks out the proper item from sys.modules and gives you a reference to it. There are a few reasons for this.
Efficiency -- Why re-evaluate code you've already evaluated?
Sane behavior
Imagine a module with a special value:
# mod.py
CONSTANT = object()
now you want to use that in foo.py and bar.py.
# bar.py
import mod
def bar():
return mod.CONSTANT
# foo.py
import mod
import bar
if bar.bar() is mod.CONSTANT:
do_something()
If the import wasn't cached, then mod.CONSTANT could be different in foo and in bar which would be very surprising.

unittest, running test from other file

I can't seem to get the Test1.test_something() in test2 to work.. not sure if it's because they are both inheriting from the same base?
Helper.py:
class baseTest(unittest.TestCase):
def setUp(self, param="Something"):
print param
pass
Test1.py
from Helper import baseTest
class test1(baseTest):
def setUp(self):
super(test1, self).setUp('foo')
def test_something(self):
assert 1 == 1, "One does not equal one."
Test2.py
from Helper import baseTest
import Test1
class test2(baseTest):
def setUp(self):
super(test2, self).setUp('bar')
def test_something(self):
Test1.test_somehing()
Now, I had this working previously, when I had the setUp for test1 and test2 within their classes, but once I had them both inherit from baseTest, I started getting a unbound method <method> must be called with Test instance as first argument (got nothing instead). Any suggestions?
The problem is that Test1.test_something() is an instance method, not a class method. So you can't just call it like that (besides, even if it is class method, it should have been Test1.test1.test_something).
One way to do it (without messing around with the unittest.TestCase mechanism):
Test2.py
import Test1
class test2(Test1.test1):
# whatever else
And you're done, test2 inherits Test1.test1.test_something() automatically. If you need your test2's test_something to do extra stuff, just do super(test2, self).test_something() within your overridden definition of test_something in test2 class.
Move the tests that are shared by both Test1 and Test2 classes into BaseTest:
test.py:
import unittest
import sys
class BaseTest(unittest.TestCase):
def setUp(self, param="Something"):
print param
pass
def test_something(self):
assert 1 == 1, "One does not equal one."
class Test1(BaseTest):
def setUp(self):
super(Test1, self).setUp('foo')
test2.py:
import test
import unittest
import sys
class Test2(test.BaseTest):
def setUp(self):
super(Test2, self).setUp('bar')

Categories