Trying to understand unittest.mock more, but not sure why its running the program twice. For simplicity, consider the code below in a file test.py:
from unittest.mock import patch
class T():
def __init__(self):
self.setup()
def setup(self):
mock_testing = patch('test.testing').start()
mock_testing.return_value = "new testing"
def testing():
return "testing"
print("Hello")
t = T()
print("Setting up")
if testing() == "testing":
print("old style")
elif testing() == "new testing":
print("new style")
When I run the script with python test.py, I get:
Hello
Hello
Setting up
new style
Setting up
old style
Why does it run the code twice? And even if it does run it twice, how come 'hello' is printed back to back, should it be printed like:
Hello
Setting up
new style
Hello
Setting up
old style
Also how can I make it so that it just runs the code once, with the mock value of 'new testing'?
This is because the script is loaded as the module __main__ first, and yet you're calling patch with test.testing, so patch will import test.py again as the test module. Since patch is called before "Setting up" is printed, the loading of the test module, as well as the printing of "Hello" by both the __main__ module and the test module, will be done before "Setting up" is printed by the __main__ module.
If you add __name__ to the arguments for print, you'll more easily see what's going on:
from unittest.mock import patch
class T():
def __init__(self):
self.setup()
def setup(self):
mock_testing = patch('test.testing').start()
mock_testing.return_value = "new testing"
def testing():
return "testing"
print(__name__, "Hello")
t = T()
print(__name__, "Setting up")
if testing() == "testing":
print(__name__, "old style")
elif testing() == "new testing":
print(__name__, "new style")
This outputs:
__main__ Hello
test Hello
test Setting up
test new style
__main__ Setting up
__main__ old style
To avoid this, you should patch __main__.testing instead, so that after the modification, the above code will output:
__main__ Hello
__main__ Setting up
__main__ new style
Related
So I've this code that mocks two times, the first time by mocking imports with:
sys.modules['random'] = MagicMock()
The second time happens inside the unittest of a function that used that import, for example a function that used random
The tests. py is:
import sys
import unittest
from unittest import mock
from unittest.mock import MagicMock
import foo
sys.modules['random'] = MagicMock()
class test_foo(unittest.TestCase):
def test_method(self):
with mock.patch('random.choice', return_value = 2):
object = foo.FooClass(3)
self.assertEqual(2, object.method(), 'Should be 2')
def test_staticmethod(self):
with mock.patch('random.choice', return_value = 2):
object = foo.FooClass(3)
self.assertEqual(2, object.method(), 'should be 2')
The original file Foo.py is:
import random
class FooClass:
def __init__(self,arg):
self.arg = arg
def method(self):
print(random.choice)
return random.choice([1,2,3])
#staticmethod
def staticmethod():
print(random.choice)
random.choice([1,2,3])
The two mocks contrarrest each other, and the mocking of random doesn't happen.
When it prints random it actually prints:
<<bound method Random.choice of <random.Random object at 0x7fe688028018>>
I want that to print a MagicMock.
Can someone help me understand what's happening? Why are they contrarresting each other?
You don't need to update the module source with sys.modules['random'] = MagicMock() without this line it works fine <MagicMock name='choice' id='...'>. patch already does all the work for the isolated temporary updating the method. See more explanation in the docs - Where to patch
I have 2 files a.py and b.py as follows:
a.py
import b.py
Test="abc"
def main(args):
global Test
if args.target=="this":
Test="klm"
b.fun()
#rest of the body which I intend to execute only once
#hence I cannot call main() again
if __name__ == "__main__":
#some arguments are parsed
args = parser.parse_args()
main(args)
b.py
import a
print a.Test
EDIT: Output:
python a.py
abc
So basically my question is why is the Test variable not getting updated in b.py and how can I make this work? Thanks.
import a
a.main()
print a.Test
a.Test = "new Value"
print a.Text
You never invoke the main function. When you import a module, __name__ is not "__main__", so your main() never runs. When you run a.py directly it will run main()
Added due to question edit:
You need to consider the ordering of the imports execution. Consider these working files.
a.py
print("Entering a")
import argparse
import b
Test="abc"
print("Id of Test: ", id(Test))
def main(args):
global Test
if args.target=="this":
Test="klm"
b.fun()
#rest of the body which I intend to execute only once
#hence I cannot call main() again
if __name__ == "__main__":
#some arguments are parsed
print('Entering main')
parser = argparse.ArgumentParser()
parser.add_argument('--target', dest='target', type=str)
args = parser.parse_args()
main(args)
b.py
print("Entering b")
import a
print a.Test
def fun():
pass
The console produces the following:
$ python a.py
Entering a
Entering b
Entering a
('Id of Test: ', 40012016L)
abc
('Id of Test: ', 40012016L)
Entering main
The problem is, when you import a python module/file, you will immediately execute all the statements in that module. As such, you have a problem with your dependencies (aka imports), because b is importing a before the value of Test is 'corrected' and then immediately acting on this.
Consider two changes. First, introduce a third file config.py that contains this configuration information and that b does not import a. Second, move all your statements that require this config in b into functions that are called/bootstrapped by a, as obviously intended.
Previous answer:
I have a solution demonstrating the issue, by only modifying b.py
def fun(): # Added because your main calls this. An error?
pass
from a import Test, main
import a
print Test # prints 'abc'
print a.Test # prints 'abc'
main()
print Test # prints 'abc'
print a.Test # prints 'klm'
Within the python interpretor, I can produce the following:
>>> import b
abc
abc
abc
klm
In your code, you create a new variable called Test with the command from a import Test that points to the original string object. You actually want to access the Test variable owned by the module a.
In a.py you run main in the if statement:
if __name__ == "__main__":
main()
Only executes main() if that is the main script. When you import the module all the code in the if block is not run because it is not the main script. To have the main method be called remove the if statement or just call main in b.py.
I am currently attempting to write unit tests for my Main.py's main() function
Here is a simplified version of my Main.py:
from Configuration import Configuration # Configuration.py is a file in the same dir
def main():
try:
Configuration('settings.ini')
except:
sys.exit(1) # Test path1
sys.exit(0) # Test path2
if __name__ == '__main__':
main()
In my Unit Tests\MainUnitTests.py I want to import ..\Main.py and fake the Configuration class in such a way that I can hit Test path1 and Test path2
I found that i can assert sys.exit() with the following:
with self.assertRaises(SystemExit) as cm:
main()
self.assertEqual(cm.exception.code, 1)
but I am having trouble overriding the from Configuration import Configuration
Thoughts?
So far I have tried the following within Unit Tests\MainUnitTests.py:
class FakeFactory(object):
def __init__(self, *a):
pass
sys.modules['Configuration'] = __import__('FakeFactory')
class Configuration(FakeFactory):
pass
Another example for demonstration:
foo.py:
from bar import a,b
x = a()
class a(object):
def __init__(self):
self.q = 2
y = a()
print x.q, y.q # prints '1 2' as intended
b() # I want this to print 2 without modifying bar.py
bar.py:
class a(object):
def __init__(self):
self.q = 1
def b():
t = a()
print t.q
when you use the import
from bar import a
it import the name directly into the module, so monkeypatching bar won't help, you need to override a directly in the main file:
def fake_a():
print("OVERRIDEN!")
main.a = fake_a
Do know that unittest has helper functions for this in the mock subpackage, I believe you could do something like:
from unittest.mock import patch
...
with patch("main.a", fake_a) as mock_obj: #there are additional things you can do with the mock_obj
do_stuff()
This would work in your first example with configuration since the class that needs to be patched is not used in the global scope although foo uses bar.a as soon as it is loaded so you would need to patch it before even loading foo:
from unittest.mock import patch
...
with patch("bar.a", fake_a) as mock_obj: #there are additional things you can do with the mock_obj
import foo #now when it loads it will be loaded with the patched name
However in this case foo.a would not be reverted at the end of the with block because it can't be caught by unittest... I really hope your actual use case doesn't use the stuff to be patched at module level.
I'm trying to make sure Testme.command() calls bar() on an instance of Dependency but I keep coming up short. I'm running this with python -m unittest tests.test_config and this code lives in tests/test_config.py in my project.
class Dependency():
def bar(self):
""" Do some expensive operation. """
return "some really expensive method"
class Testme():
def __init__(self):
self.dep = Dependency()
def command(self):
try:
self.dep.bar()
return True
except NotImplementedError:
return False
import unittest
from unittest.mock import Mock
class TestTestme(unittest.TestCase):
def test_command(self):
with (unittest.mock.patch('tests.test_config.Dependency')) as d:
d.bar.return_value = 'cheap'
t = Testme()
t.command()
d.bar.assert_called_once_with()
When I run it, it fails like bar() never got called: AssertionError: Expected 'bar' to be called once. Called 0 times.
How should I test that Testme().command() calls Dependency().bar()?
Try printing by doing
print self.dep.bar()
and
print d.bar.assert_called_once_with()
See if it outputs the correct value of "some really expensive method"
Below program:
import unittest
class my_class(unittest.TestCase):
def setUp(self):
print "In Setup"
self.x=100
self.y=200
def test_case1(self):
print "-------------"
print "test case1"
print self.x
print "-------------"
def test_case2(self):
print "-------------"
print "test case2"
print self.y
print "-------------"
def tearDown(self):
print "In Tear Down"
print " "
print " "
if __name__ == "__main__":
unittest.main()
Gives the output:
>>> ================================ RESTART ================================
>>>
In Setup
-------------
test case1
100
-------------
In Tear Down
.In Setup
-------------
test case2
200
-------------
In Tear Down
.
----------------------------------------------------------------------
Ran 2 tests in 0.113s
OK
>>>
>>>
Questions:
what's the meaning of: if __name__ == "__main__": unittest.main()?
Why do we have double underscores prefixed and postfixed for name and main?
Where will the object for my_class be created?
The if __name__ == "__main__": bit allows your code to be imported as a module without invoking the unittest.main() code - that will only be run if this code is invoked as the main entry point of your program (i.e. if you called it like python program.py if your program was in program.py).
The prefix and postfix of double underscores means:
__double_leading_and_trailing_underscore__ : "magic" objects or attributes that live in user-controlled namespaces. E.g. __init__ , __import__ or __file__ . Never invent such names; only use them as documented.
That comes from the PEP 8 Style Guide - this is a really useful resource to read and internalize.
Finally, your my_class class will be instantiated within the unittest framework as it runs, as it inherits from unittest.TestCase.