Testing methods are called on object created - python

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)

Related

Is it possible to check the call parameters in the test?

is it possible to check in the test with what parameters the method is called and what result it returns, if we call the main method run which calls the method I'm interested in - self.get_request().
file.py
class A:
def run():
some logic...
request = self.get_request()
some logic...
return response
test.py
from file.py import A
def test():
"""
Inside this test, I want to check the parameters and the value returned by the
get_request method, but I don't want to check it separately
I want to check it by calling the parent method - run
"""
instance = A()
response = instance.run()
assertions logic for instance.get_request..
I know that it is possible to mock a method and then we have access to the number of calls, parameters, etc. If what I'm asking is possible in some way through mock, I just want to add that my mock would have to have the same logic as the method it mocks (be the same).
What you are asking for is probably the wraps argument that can be used in patch - this allows you to mock a function, while it still retains the previous (or some other) functionality (note that the argument itself is described under Mock). As with any mock, this does allow you to test the calls and call args, but does not allow you to check the return value of the function. This has to be tested via its side effects (in your case via the returned response which should depend on the return value of get_request).
Here is an illustration for your case:
from unittest import mock
class A:
def run(self):
request = self.get_request(21)
return request
def get_request(self, foo):
return foo * 2
def test_run():
instance = A()
with mock.patch.object(instance, "get_request", wraps=instance.get_request) as mocked:
assert instance.run() == 42
mocked.assert_called_once_with(21)
In this case the mock calls the real get_request method and returns its result, while recording the call and the call args.
I added some argument to get_request for demonstration, and returned the result of the call directly in run - in your case this will differ of course, but the idea should be the same.

Mock dns resolver answer with python

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()

Benefit of using custom initialize function instead of `__init__` in python

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.

How to call self in a mock method of an object in Python?

I try to test some codes which don't return anything but save the result to the DB. By mocking the save method, I wish to check whether things have been processed correctly:
def mock_save(self):
assert(self.attr, 'dest_val')
with mock.patch.object(Item, "save", create=True) as save:
save.side_effect = mock_save
func_to_call() //in func_to_call, I call item.save()
However, it seems that this is not allowed. It says that the number of argument mismatch.
If I do def mock_save(), it won't work.
How can I have a reference to the object which the mock method act upon too? (I saw it in another thread that is applicable to __init__ method which can be called directly from the class).
You need autospec=True
def mock_save(self):
assert self.attr == 'dest_val'
with mock.patch.object(Item, "save", autospec=True) as save:
save.side_effect = mock_save
func_to_call()
Sometime you just want to check that a method has been called, but you have no control over where its class is instantiated or the method called. Here's an approach that could save some time to whoever stumble upon this pattern:
# first get a reference to the original unbound method we want to mock
original_save = Item.save
# then create a wrapper whose main purpose is to record a reference to `self`
# when it will be passed, then delegates the actual work to the unbound method
def side_fx(self, *a, **kw):
side_fx.self = self
return original_save(self, *a, **kw)
# you're now ready to play
with patch.object(Item, 'save', autospec=True, side_effect=side_fx) as mock_save:
data = "the data"
# your "system under test"
instance = SomeClass()
# the method where your mock is used
instance.some_method(data)
# you now want to check if it was indeed called with all the proper arguments
mock_save.assert_called_once_with(side_fx.self, data)

how mock only one method called within the object you are testing

I want to test a method but mock out other methods that it calls. I created this simple example that should illustrate the concept:
class myClass():
def one_method(self):
print "hey"
def two_deep(self):
self.one_method()
def three_deep(self):
self.two_deep()
I was using a python mock framework called Mox and wrote the following code to do this:
def test_partial(self):
self_mox = mox.Mox()
some_object = myClass()
## 1. make your mock
my_mock = mox.MockObject(some_object)
my_mock.one_method().AndReturn('some_value')
self_mox.ReplayAll()
ret = my_mock.three_deep() ## *** SEE NOTE BELOW called "comment":
self_mox.VerifyAll()
Comment:
I thought that if I called this mock on a method that hadn't been overwritten, then the mock would default to the original code, then I could get the chain of calls that I want, with the last call being replaced... but it doesn't do this. I can't figure out how to embed a mock object inside a test object that doesn't have an inserting method.
I looked into Partial Mocks and Chained Mocks to solve this, but I couldn't find a way to pull this off.
Thanks for any help :)
-- Peter
Check documentation for StubOutWithMock:
https://code.google.com/p/pymox/wiki/MoxDocumentation#Stub_Out
https://code.google.com/p/pymox/wiki/MoxRecipes#Mock_a_method_in_the_class_under_test.
So what you needed is:
def test_partial(self):
self_mox = mox.Mox()
# Create the class as is, instead of doing mock.
some_object = myClass()
# Stub your particular method using the StubOutWithMock.
m.StubOutWithMock(some_object, "one_method")
some_object.one_method().AndReturn('some_value')
self_mox.ReplayAll()
ret = some_object.three_deep()
self_mox.UnsetStubs()
self_mox.VerifyAll()

Categories

Resources