I have a method that builds a query, pass it to a _make_query method in charge of resolving that query (using dns resolver) and return the answer. Then, the parent method do some stuff from the answer. I'd like to unit test the parent method ; for that I guess the best way would be to mock the _make_query method to return different outcomes and test how the parent method respond to it.
However I'm having a hard time mocking the method to return the same object returned by the dns resolver.
Here is the _make_query method:
def _make_query(self, query):
query_resolver = resolver.Resolver()
return query_resolver.query(query, 'SRV')
code of the calling method :
def _get_all_databases(self, database_parameters):
query = self._format_dns_query(database_parameters)
answers = self._make_query(query)
databases = []
for answer in answers:
databases.append(
Database(
answer.target, answer.port, answer.weight,
database_parameters.db_name
))
return databases
(also private as the main method get_database has then to pick a database from the list returned)
I have a mock to return what I want from this method in my unit tests, however I don't know how to reproduce the object being returned by the resolver.query() method. It should return a dns.resolver.Answer, which in turn contains a list of dns.rdtypes.IN.SRV.SRV it seems. Is there a simple way to do it?
You can either mock the __make_query() method (a bit harder, since you need to manually mangle the name now to match the class-private namespace protection, see What is the meaning of single and double underscore before an object name?), or mock the Resolver() object.
You don't have to exactly match the instances produced here, you only need to produce enough of their attributes to pass muster. For the SRV class from the dnspython project, all you need is an object with port, priority, target and weight attributes, with target behaving like a dns.name.Name instance. The latter is a bit more complex, but you only need to stub out the things your code needs.
You can trivially do this with the unittest.mock library, with or without speccing out the objects precisely. For your code, all you use is 3 attributes, so your mock only ever needs to return a list with nothing more than that.
You can use the create_autospec() function to generate a mock object that's limited to the attributes the original class supports. This can help detect bugs where your code uses an attribute or method that the original classes would never allow. If you don't use a spec, then the default is to produce mock objects that allow all attributes, pretending that those attributes exist (and each such access would produce more mock objects).
So, if you need SRV instances, then I'd use:
import unittest
from unittest import mock
from dns.rdtypes.IN.SRV import SRV
def make_mock_srv(target, port, weight):
mock_srv = mock.create_autospec(SRV)
mock_name = mock.create_autospec(Name)
instance = mock_srv.return_value
instance.target = target
instance.port = port
instance.weight = weight
return instance
class TestMakeQuery(unittest.TestCase):
#mock.patch('dns.resolver.Resolver')
def test_make_query(self, mock_resolver):
mock_resolver_instance = mock_resolver.return_value # the object returned by Resolver()
mock_resolver_instance.query.return_value = [
make_mock_srv('foo.', 1234, 2),
make_mock_srv('bar.', 42, 4),
]
# run your test, which calls _make_query, which calls Resolver().query()
Related
I'm new to Python so forgive me if this is basic. I have a method under test and in that method, I instantiate an object and call methods on it and want to test that those are called correctly (worth pointing out that this code is pre-existing and I'm merely adding to it, with no existing tests).
Method under test
def dispatch_events(event):
dispatcher = Dispatcher()
dispatcher.register("TopicOne")
dispatcher.push(event)
Expected test
# Some patch here
def test_dispatch_events(self, mock_dispatcher):
# Given
event = { "some_prop": "some_value" }
# When
Class.dispatch_events(event)
# Then
mock_dispatcher.register.assert_called_once_with("TopicOne")
mock_dispatcher.push.assert_called_once_with(event)
Coming from a .NET background my immediate thought is to pass Dispatcher into dispatch_events as a parameter. Then presumably, I can pass in a MagicMock version. Or I thought that you might be able to patch the __init__ method on the Dispatcher and return a MagicMock. Before I continue with this I wanted to know whether a) it's possible and b) what's the best practice for testing this (fully accepting that writing a better method might be that best practice).
Make dispatcher an argument, and you don't need to patch anything.
def dispatch_events(event, dispatcher=None):
if dispatcher is None:
dispatcher = Dispatcher()
dispatcher.register("TopicOne")
dispatcher.push(event)
def test_dispatch_events(self):
event = {"some_prop": "some_value"}
mock_dispatcher = Mock()
Class.dispatch_events(event, mock_dispatcher)
mock_dispatcher.register.assert_called_once_with("TopicOne")
mock_dispatcher.push.assert_called_once_with(event)
If that's not an option, the correct thing to mock in most cases will be Dispatcher.__new__ or some.module.Dispatcher itself.
# The exact value of 'some.module' depends on how the module that
# defines dispatch_events gets access to Dispatcher.
#mock.patch('some.module.Dispatcher')
def test_dispatch_events(self, mock_dispatcher):
event = {"some_prop": "some_value"}
Class.dispatch_events(event)
mock_dispatcher.register.assert_called_once_with("TopicOne")
mock_dispatcher.push.assert_called_once_with(event)
I was looking into the following code.
On many occasions the __init__ method is not really used but there is a custom initialize function like in the following example:
def __init__(self):
pass
def initialize(self, opt):
# ...
This is then called as:
data_loader = CustomDatasetDataLoader()
# other instance method is called
data_loader.initialize(opt)
I see the problem that variables, that are used in other instance methods, could still be undefined, if one forgets to call this custom initialize function. But what are the benefits of this approach?
Some APIs out in the wild (such as inside setuptools) have similar kind of thing and they use it to their advantage. The __init__ call could be used for the low level internal API while public constructors are defined as classmethods for the different ways that one might construct objects. For instance, in pkg_resources.EntryPoint, the way to create instances of this class is to make use of the parse classmethod. A similar way can be followed if a custom initialization is desired
class CustomDatasetDataLoader(object):
#classmethod
def create(cls):
"""standard creation"""
return cls()
#classmethod
def create_with_initialization(cls, opt):
"""create with special options."""
inst = cls()
# assign things from opt to cls, like
# inst.some_update_method(opt.something)
# inst.attr = opt.some_attr
return inst
This way users of the class will not need two lines of code to do what a single line could do, they can just simply call CustomDatasetDataLoader.create_with_initialization(some_obj) if that is what they want, or call the other classmethod to construct an instance of this class.
Edit: I see, you had an example linked (wish underlining links didn't go out of fashion) - that particular usage and implementation I feel is a poor way, when a classmethod (or just rely on the standard __init__) would be sufficient.
However, if that initialize function were to be an interface with some other system that receives an object of a particular type to invoke some method with it (e.g. something akin to the visitor pattern) it might make sense, but as it is it really doesn't.
I have situation similar to:
class BaseClient(object):
def __init__(self, api_key):
self.api_key = api_key
# Doing some staff.
class ConcreteClient(BaseClient):
def get_some_basic_data(self):
# Doing something.
def calculate(self):
# some staff here
self.get_some_basic_data(param)
# some calculations
Then I want to test calculate function using mocking of get_some_basic_data function.
I'm doing something like this:
import unittest
from my_module import ConcreteClient
def my_fake_data(param):
return [{"key1": "val1"}, {"key2": "val2"}]
class ConcreteClientTest(unittest.TestCase):
def setUp(self):
self.client = Mock(ConcreteClient)
def test_calculate(self):
patch.object(ConcreteClient, 'get_some_basic_data',
return_value=my_fake_data).start()
result = self.client.calculate(42)
But it doesn't work as I expect.. As I thought, self.get_some_basic_data(param) returns my list from my_fake_data function, but it looks like it's still an Mock object, which is not expected for me.
What is wrong here?
There are two main problems that you are facing here. The primary issue that is raising the current problem you are experiencing is because of how you are actually mocking. Now, since you are actually patching the object for ConcreteClient, you want to make sure that you are still using the real ConcreteClient but mocking the attributes of the instance that you want to mock when testing. You can actually see this illustration in the documentation. Unfortunately there is no explicit anchor for the exact line, but if you follow this link:
https://docs.python.org/3/library/unittest.mock-examples.html
The section that states:
Where you use patch() to create a mock for you, you can get a
reference to the mock using the “as” form of the with statement:
The code in reference is:
class ProductionClass:
def method(self):
pass
with patch.object(ProductionClass, 'method') as mock_method:
mock_method.return_value = None
real = ProductionClass()
real.method(1, 2, 3)
mock_method.assert_called_with(1, 2, 3)
The critical item to notice here is how the everything is being called. Notice that the real instance of the class is created. In your example, when you are doing this:
self.client = Mock(ConcreteClient)
You are creating a Mock object that is specced on ConcreteClient. So, ultimately this is just a Mock object that holds the attributes for your ConcreteClient. You will not actually be holding the real instance of ConcreteClient.
To solve this problem. simply create a real instance after you patch your object. Also, to make your life easier so you don't have to manually start/stop your patch.object, use the context manager, it will save you a lot of hassle.
Finally, your second problem, is your return_value. Your return_value is actually returning the uncalled my_fake_data function. You actually want the data itself, so it needs to be the return of that function. You could just put the data itself as your return_value.
With these two corrections in mind, your test should now just look like this:
class ConcreteClientTest(unittest.TestCase):
def test_calculate(self):
with patch.object(ConcreteClient, 'get_some_basic_data',
return_value=[{"key1": "val1"}, {"key2": "val2"}]):
concrete_client = ConcreteClient(Mock())
result = concrete_client.calculate()
self.assertEqual(
result,
[{"key1": "val1"}, {"key2": "val2"}]
)
I took the liberty of actually returning the result of get_some_basic_data in calculate just to have something to compare to. I'm not sure what your real code looks like. But, ultimately, the structure of your test in how you should be doing this, is illustrated above.
So lately in Python I started using the unittest library. However, one thing that I cannot understand (and I've tried looking this up for hours and hours...) is why you would use the patch decorator over an explicit MagicMock objects.
To be more specific, below is my code that I am attempting to test. Some quick notes:
The code is attempting to test a simple menu class for some restaurant.
In the setUp method, I am preparing the instantiated Menu object by storing some instantiated Food objects (which in this case are replaced by MagicMock objects).
In the testFindItem method, I am attempting to find and return a Food object from the menu via searching for it's name. Then I compare the found object with the Food object (MagicMock object in this case) it is suppose to be.
Now that being said, observe how in the setUp method I replaced self.bread and self.cardboard by MagicMock objects instead of Food objects. The code works, and that is great but an alternative would be to use a patch decorator that overrides the Food class.
TL;DR: Why would that (i.e. using a patch) be better or worse in this case? Or rather as mentioned before, why use patch decorator over explicit MagicMock objects?
Oh on a side note, the closest answer that I have found is another post which discusses the difference between patch and mock but not why you would use one over the other: Mocking a class: Mock() or patch()?
class MenuTest(unittest.TestCase):
"""
Unit test class for Menu class.
"""
def setUp(self):
"""
Prepares a menu to be tested against using mock objects.
"""
self.bread = MagicMock()
self.cardboard = MagicMock()
self.bread.name = "bread"
self.cardboard.name = "cardboard"
foodItems = [self.cardboard, self.bread]
self.menu = Menu(foodItems)
def testFindItem(self):
"""
Tests whether a specified food item can be found on the menu.
"""
# Items on the menu
self.assertEqual(self.menu.findItem("bread"), self.bread)
self.assertEqual(self.menu.findItem("cardboard"), self.cardboard)
# Items not on the menu
with self.assertRaises(NameError):
self.menu.findItem("salvation")
This isn't the use case for patch. The reason you use that is when you want to replace an object that is defined elsewhere. Here, you're explicitly instantiating the Menu and passing in the things you want to call assertions on, so patch is not useful; but there are plenty of times when the class under test creates its own objects, or gets them from other parts of the code, and that's when you'd use patch.
When mocking classes or methods when writing unittests in Python, why do I need to use #patch decorator? I just could replace the method with Mock object without any patch annotation.
Examples:
class TestFoobar(unittest.TestCase):
def setUp(self):
self.foobar = FooBar()
# 1) With patch decorator:
#patch.object(FooBar, "_get_bar")
#patch.object(FooBar, "_get_foo")
def test_get_foobar_with_patch(self, mock_get_foo, mock_get_bar):
mock_get_bar.return_value = "bar1"
mock_get_foo.return_value = "foo1"
actual = self.foobar.get_foobar()
self.assertEqual("foo1bar1", actual)
# 2) Just replacing the real methods with Mock with proper return_value:
def test_get_foobar_with_replacement(self):
self.foobar._get_foo = Mock(return_value="foo2")
self.foobar._get_bar = Mock(return_value="bar2")
actual = self.foobar.get_foobar()
self.assertEqual("foo2bar2", actual)
Could someone produce an example, where patch decorator is good and replacing is bad?
We have always used patch decorator with our team, but after reading this comment for a post, I got the idea that maybe we could write nicer-looking code without the need of patch decorators.
I understand that patching is temporary, so maybe with some cases, it is dangerous to not use patch decorator and replace methods with mock instead? Could it be that replacing objects in one test method can affect the result of the next test method?
I tried to prove this, but came up empty: both tests pass in the next code:
def test_get_foobar_with_replacement(self):
self.foobar._get_foo = Mock(return_value="foo2")
self.foobar._get_bar = Mock(return_value="bar2")
actual = self.foobar.get_foobar()
self.assertIsInstance(self.foobar._get_bar, Mock)
self.assertIsInstance(self.foobar._get_foo, Mock)
self.assertEqual("foo2bar2", actual)
def test_get_foobar_with_real_methods(self):
actual = self.foobar.get_foobar()
self.assertNotIsInstance(self.foobar._get_bar, Mock)
self.assertNotIsInstance(self.foobar._get_foo, Mock)
self.assertIsInstance(self.foobar._get_bar, types.MethodType)
self.assertIsInstance(self.foobar._get_foo, types.MethodType)
self.assertEqual("foobar", actual)
Full source code (Python 3.3): dropbox.com/s/t8bewsdaalzrgke/test_foobar.py?dl=0
patch.object will restore the item you patched to its original state after the test method returns. If you monkey-patch the object yourself, you need to restore the original value if that object will be used in another test.
In your two examples, you are actually patching two different things. Your call to patch.object patches the class FooBar, while your monkey patch patches a specific instance of FooBar.
Restoring the original object isn't important if the object will be created from scratch each time. (You don't show it, but I assume self.foobar is being created in a setUp method, so that even though you replace its _get_foo method, you aren't reusing that specific object in multiple tests.)