in python, how to manipulate namespace of an instance - python

The question is in context of unit testing.
I have created an instance of the class I am testing, and trying to test one of its methods. The method uses data it gets from different class defined in separate module. I am going to mock that module.
How I can access my instance's name space - I have to do it before running the method I am testing, to mock module which contain definition of the class my method is getting data from?

I am going to create an example here which I think parallels what you are trying to do.
Say you have some class that we'll call Data that is defined in the module foo. The foo module imports bar and a method of foo.Data calls bar.get_data() to populate itself.
You want to create a module test that will create an instance of foo.Data, but instead of using the actual module bar you want that instance to use a mocked version of this.
You can set this up by importing foo from your test module, and then rebinding foo.bar to your mocked version of the module.
Here is an example of how this might look:
bar.py:
def get_data():
return 'bar'
foo.py:
import bar
class Data(object):
def __init__(self):
self.val = bar.get_data()
if __name__ == '__main__':
d = Data()
print d.val # prints 'bar'
test.py:
import foo
class bar_mock(object):
#staticmethod
def get_data():
return 'test'
if __name__ == '__main__':
foo.bar = bar_mock
d = foo.Data()
print d.val # prints 'test'
Although this will get you by for a simple test case, you are probably better off looking into a mocking library to handle this for you.

Related

python unittest.mock.patch strange behaviour

I use unittest in my testing. I import a class in yhab.main package as...
from yhab.blah import SomeClass
def some_func():
some_instance = SomeClass()
return some_instance.method()
yhab.blah.SomeClass is defined as...
class SomeClass:
def method(self):
return 'hello'
And then I write a test like this...
#mock.patch('yhab.blah.SomeClass')
def test_mock_of_blah_someclass(mock_some_class):
assert some_func() != 'hello'
the invocation of method() calls the real instance, not a mock.
But if I do this...
#mock.patch('yhab.main.SomeClass')
def test_mock_of_main_someclass(mock_some_class):
assert some_func() != 'hello'
the invocation of method() calls the mock, not the real instance and the test passes.
Why is that?
I was thinking that python must make some sort of copy of the class definition when an import happens, but I wrote a test that proves that to not be the case.
The docs say the following, which kind of eludes to this, but it doesn't really say it outright, and IMO doesn't really explain it, especially for a python newb...
Patching a class replaces the class with a MagicMock instance. If the
class is instantiated in the code under test then it will be the
return_value of the mock that will be used.
Do the docs need to be updated to be clear?
After you import SomeClass from yhab.blah, it ends up in the yhab.main namespace, not in the yhab.blah namespace.
Try to use #mock.patch('yhab.main.SomeClass') instead of #mock.patch('yhab.blah.SomeClass').

Mocking a Python object without method calls

Imagine a class like so:
class Foo():
def method_1(self):
bar = Bar()
bazz = Bazz(bar)
return bazz.method_2()
For unit testing, how can we mock the Bar object when we never call any methods on it, we're just passing it as a parameter to the Bazz constructor? (Yes, this is not ideal, but this pattern can be found in a top-level class wiring together different objects via dependency injection).
You do call the Bar object, when you execute: bar = Bar(), so you can easily mock it:
mock_bar = mocker.MagicMock(name='Bar')
mocker.patch('foo.Bar', new=mock_bar)
# mock_foo.return_value = the new mocked object

Python - How to properly mock the cls argument in a class method to reference static variable

Background
Relatively new to Python and its unittest module. Having trouble mocking a static class variable within test.
(Only when the original class method is referencing its own class variable by its first argument: cls)
Example:
Simplified version of the class and class method being tested:
a.py
class A:
# class variable
my_list = []
#classmethod
def my_method(cls, item):
print cls # [] unable to mock this, why?
print A # [1,2,3] mocked as intended
cls.my_list.append(item)
Test:
import unittest
from mock import patch
from a import A
class Test(unittest.testCase):
def test_my_method(self):
with patch("a.A") as mock_A:
# mocking the class variable
mock_A.my_list = [1,2,3]
# test call class method
A.my_method(4)
# assert the appended list to expected output
self.assertEqual(mock_A.my_list, [1,2,3,4])
# should evaluate to true, but fails the test
if __name__ == "__main__":
unittest.main()
Question:
Why does mock only patches the A reference and not the cls reference?
In what direction should the solution be, in order to successfully patch the cls argument as well, so class method can pass the test shown above.
You imported A already within the test module, so you already have a reference to the original unpatched A, and this is what you call my_method on.
Why does mock only patches the A reference and not the cls reference?
Because that's what you patched. Patch works by intercepting on name lookups, it doesn't (and can't) literally replace objects in place. When you want to patch out an object that has multiple names (A and cls, in this case) then you'd have to patch out every name lookup.
In what direction should the solution be, in order to successfully patch the cls argument as well, so class method can pass the test shown above.
It will be better to patch out the class attribute directly:
class Test(unittest.TestCase):
def test_my_method(self):
with patch("a.A.my_list", [1,2,3]):
A.my_method(4)
self.assertEqual(A.my_list, [1,2,3,4])
self.assertEqual(A.my_list, []) # note: the mock is undone here

Python using function like variable

I've got a Python module which has several variables with hard-coded values which are used throughout the project. I'd like to bind the variables somehow to a function to redirect to a config file. Is this possible?
# hardcoded_values.py
foo = 'abc'
bar = 1234
# usage somewhere else in another module
from hardcoded_values import *
print foo
print bar
What I want to do is change only hardcoded_values.py, so that print foo transparently calls a function.
# hardcoded_values.py
import config
foo = SomeWrapper(config.get_value, 'foo') # or whatever you can think of to call config.get_value('foo')
...
config.get_value would be a function that is called with parameter 'foo' when using variable foo (as in print foo).
I'm pretty sure that you can't do what you want to do if you import like from hardcoded_values import *.
What you want to do is to set foo to some function, and then apply the property decorator (or equivalent) so that you can call foo as foo rather than foo(). You cannot apply the property decorator to modules for reasons detailed here: Why Is The property Decorator Only Defined For Classes?
Now, if you were to import hardcoded_values then I think there is a way to do what you want to hardcoded_values.foo. I have a pretty good feeling that what I am about to describe is a BAD IDEA that should never be used, but I think it is interesting.
BAD IDEA???
So say you wanted to replace a constant like os.EX_USAGE which on my system is 64 with some function, and then call it as os.EX_USAGE rather than os.EX_USAGE(). We need to be able to use the property decorator, but for that we need a type other than module.
So what can be done is to create a new type on the fly and dump in the __dict__ of a module with a type factory function that takes a module as an argument:
def module_class_factory(module):
ModuleClass = type('ModuleClass' + module.__name__,
(object,), module.__dict__)
return ModuleClass
Now I will import os:
>>> import os
>>> os.EX_USAGE
64
>>> os.getcwd()
'/Users/Eric'
Now I will make a class OsClass, and bind the name os to an instance of this class:
>>> OsClass = module_class_factory(os)
>>> os = OsClass()
>>> os.EX_USAGE
64
>>> os.getcwd()
'/Users/Eric'
Everything still seems to work. Now define a function to replace os.EX_USAGE, noting that it will need to take a dummy self argument:
>>> def foo(self):
... return 42
...
...and bind the class attribute OsClass.EX_USAGE to the function:
>>> OsClass.EX_USAGE = foo
>>> os.EX_USAGE()
42
It works when called by the os object! Now just apply the property decorator:
>>> OsClass.EX_USAGE = property(OsClass.EX_USAGE)
>>> os.EX_USAGE
42
now the constant defined in the module has been transparently replaced by a function call.
You definitely cannot do this if the client code of your module uses from hardcoded_variables import *. That makes references to the contents of hardcoded_variables in the other module's namespace, and you can't do anything with them after that.
If the client code can be changed to just import the module (with e.g. import hardcoded_variables) and then access its attributes (with hardcoded_variables.foo) you do have a chance, but it's a bit awkward.
Python caches modules that have been imported in sys.modules (which is a dictionary). You can replace a module in that dictionary with some other object, such as an instance of a custom class, and use property objects or other descriptors to implement special behavior when you access the object's attributes.
Try making your new hardcoded_variables.py look like this (and consider renaming it, too!):
import sys
class DummyModule(object):
def __init__(self):
self._bar = 1233
#property
def foo(self):
print("foo called!")
return "abc"
#property
def bar(self):
self._bar += 1
return self._bar
if __name__ != "__main__": # Note, this is the opposite of the usual boilerplate
sys.modules[__name__] = DummyModule()
If I understand correctly, you want your hardcoded_variables module evaluated every time you try to access a variable.
I would probably have hardcoded_variables in a document (e.g. json?) and a custom wrapper function like:
import json
def getSettings(var):
with open('path/to/variables.json') as infl:
data = json.load(infl)
return infl[var]

Unit test a method of mocked object

I am trying to get a hang of mocking objects, and seem to by confused by something very basic. I am trying to mock object MyClass and then unit test one of its methods. here is my code:
import mock
import unittest
class MyClass(object):
def __init__(self, a):
self.a = a
def add_two(self):
return self.a + 2
class TestMyClass(unittest.TestCase):
#mock.patch('__main__.MyClass')
def test_add_two(self, dummy_mock):
m_my_class = mock.Mock()
m_my_class.a = 10
result = m_my_class.add_two() # I would expect the result to be 12
import ipdb;ipdb.set_trace()
self.assert_equal(result, 12)
if __name__ == '__main__':
unittest.main()
In m_my_class.a = 10 I set value of a to to and then in m_my_class.add_two() I add a two, shouldn't I get 12? However, result is:
16 import ipdb;ipdb.set_trace()
---> 17 self.assert_equal(result, 12)
18
ipdb> result
<Mock name='mock.add_two()' id='18379792'>
What am I missing?
Since I am passing the location of the class via decorator to the test method #mock.patch('__main__.MyClass'), shouldn't mocked have all the methods? Because if not, then why does it matter what class we include in the decorator?
Edit:
When I run this code, I still get the same thing.
class TestMyClass(unittest.TestCase):
#mock.patch('__main__.MyClass')
def test_add_two(self, dummy_mock):
dummy_mock.a = 10
result = dummy_mock.add_two()
import ipdb;ipdb.set_trace()
self.assert_equal(result, 12)
Result:
ipdb> result
<MagicMock name='MyClass.add_two()' id='38647312'>
Patching the class is almost certainly not what you want to do here. For example, if you changed your test method to this:
class TestMyClass(unittest.TestCase):
#mock.patch('__main__.MyClass')
def test_add_two(self, dummy_mock):
m_my_class = MyClass(5)
print m_my_class
You will find that rather than getting what you expect:
<__main__.MyClass object at 0x0000000002C53E48>
You'll get this:
<MagicMock name='MyClass()' id='46477888'>
Patching the class in the method means that any time within the method that something tries to instantiate the class it will instead get a mock object. In your particular case, calling MyClass(5) will return the same mock object as calling dummy_mock would. This allows you to set up the mock object so that when you go to test your code the mock object will behave as you want it to.
You really would only use this for dependencies, not the class you are testing. So for example, if your class retrieved data from SQL, you'd patch the SQL class to give your class a mock instead of the normal SQL connection. This allows you to test a class in isolation, without having to worry about externals (like the SQL) getting in the way.
In your example though, you seem to be trying to test a method in isolation. A way you could do that is to extract the function from the method and use that. In code:
def test_add_two(self):
test_mock = mock.Mock()
test_mock.add_two = MyClass.add_two.__func__
test_mock.a = 10
result = test_mock.add_two(test_mock)
self.assert_equal(result, 12)
Normally you wouldn't have to pass in an argument for the self argument, but as here we've pulled out the function you do need to pass in the self argument. If you want you can turn the function into a method bound to your mock object, like this:
import types
...
test_mock.add_two = types.MethodType(MyClass.add_two.__func__, test_mock, test_mock.__class__)
result = test_mock.add_two()
If the function you are testing calls any other methods, you'll need to either do this or mock it out for each of the methods.
I would advise against using this strategy too much, in part because of needing to take care of methods that the tested method calls. Of course, being able to mock out the methods it depends on may be exactly what you're trying to do. In any case, it requires the unit tests to have a pretty deep understanding of how the method works, and not just of what it is supposed to produce. That makes the test very fragile, making it so that you are likely to see the test break far more often than the method you are testing.
Why are you mocking your SUT? This is generally something that you should avoid doing because it introduces the risk that you will not be testing what you think you're testing.
The point of a unit test is to verify the behavior of a unit in complete isolation. One unit typically collaborates with other units in order to provide some useful functionality. Test doubles (mocks, fakes, etc.) are the tools used to achieve this isolation. In a unit test, collaborators of the SUT are replaced with test doubles in order to minimize the number of moving parts.
Your SUT, MyClass, doesn't appear to have any collaborators. As such, no test doubles are necessary to test this unit in isolation (it's already self-contained). This allows you to greatly simplify your unit test:
import mock
import unittest
class MyClass(object):
def __init__(self, a):
self.a = a
def add_two(self):
return self.a + 2
class TestMyClass(unittest.TestCase):
def test_add_two(self):
m_my_class = MyClass()
m_my_class.a = 10
result = m_my_class.add_two() # I would expect the result to be 12
import ipdb;ipdb.set_trace()
self.assert_equal(result, 12)
if __name__ == '__main__':
unittest.main()
Edit: The following code demonstrates how a mock object might be used. (Disclaimer: I don't normally work in Python, so my code is probably not very idiomatic. Hopefully the core point still makes sense, though.)
In this example, MyClass adds a value provided by a collaborator, instead of a hardcore value (2).
import mock
import unittest
class MyClass(object):
def __init__(self, a, get_value):
self.a = a
self.get_value = get_value
def add_value(self):
return self.a + self.get_value()
class TestMyClass(unittest.TestCase):
def test_add_value(self):
m_test_value = 42
m_test_a = 10
m_my_class = MyClass()
m_get_test_value = mock.Mock(return_value=m_test_value)
m_my_class.a = test_a
result = m_my_class.add_value()
import ipdb;ipdb.set_trace()
self.assert_equal(result, m_test_a + m_test_value)
if __name__ == '__main__':
unittest.main()
The above example uses a mock object, instead of patching a class. Here is a pretty good explanation of the difference:
Mocking a class: Mock() or patch()?

Categories