How to mock multiple functions in python? - python

I am new to unit testing and mocking in python, in below scenario I know how to mock the get_name() which doesn't have any parameter mock example, but I am not able to mock the below scenario which take age as an argument. Could you please help me to fix mock test_name function below?
# data_source.py
def get_name(a):
return "Alice"+str(a)
def get_age():
return 30
The Person class exposes a method that fetches data from the data source:
# person.py
from data_source import get_name
class Person(object):
def name(self):
age = get_age()
return get_name(age)
from mock import patch
from person import Person
#patch('person.get_name')
def test_name(mock_get_name):
mock_get_name.return_value = "Bob"
person = Person()
name = person.name()
assert name == "Bob"
Thanks in advance!

First of all, apart from importing get_name, you also need to import get_age, since you use it in the Person class. Second, there is nothing like person.get_name defined ever. So you can't patch that. Instead, you probably wanted to patch data_souce.get_name.
But unfortunately, that doesn't work, because data_source is a python module, and get_name is a method within it that you want to redefine. The patch decorator would be good if get_name were a method within a DataSource class, for example. I don't know the exact reason why it doesn't work, because I did not take a deep dive into the implemenation details of the mock library, but the intention of the library is different than how you want to use it.
To solve the problem, you can eiter turn data_source into a class, or you can temporarily change the meaning of the name get_name, by assigning a different function or a lambda to it:
import data_source
def test_person():
# replace the function
data_source._real_get_name = data_source.get_name
data_source.get_name=lamba a: "Bob"
# do some work
person = Person()
name = person.name()
# after use of the get_name function, put the original function back
data_source.get_name=data_source._real_get_name
# assert post condition
assert name=="Bob"
Of course, changing what functions do severely affects your program and should be done with care, probably only for testing. Make sure you always put the original function back, even if an error is thrown unexpectedly.

Related

#property does not work when variables are not in a class, but in a module

I have a code like below. My requirement is to fill BagA and BagB once and only once. So, I do not have a class but have written code in a module. I have __BagA and __BagB with underscores because I do not want it to get changed from outside. I have a getter as shown using #property decorator. But it does not work.
module.py:
import csv
import sys
import threading
__BagA = list()
__BagB = dict()
__lock = threading.Lock()
#property
def BagA():
if not __BagA:
raise("Call Initialize() first")
else:
return __BagA
#property
def BagB():
if not __BagB:
raise("Call lookup.Initialize() first")
else:
return __BagB
def __get__BagA(directory):
#logic to populate BagA
BagA=some list
def __get__BagB(directory):
#logic to populate BagB
BagB=dict after processing the logic
def initialize(directory):
__lock.acquire()
__get__BagA(directory)
__get__BagB(directory)
__lock.release()
Main script:
import module
module.initialize("dir")#this works. I see all bags getting populated
#Below does not work
module.BagA #This gives an object with some fget and fset and not the value of BagA
#below works
module.__BagA
One more problem is that instead of __BagA which could still be modified from outside, I could write BagA and have #Bag.setter decorator and #BagA.deleter decorator which returns an exception saying 'you cannot modify this'.
These are also not working and I do not want to write them separately but in a single line like below because they have same behavior. Both separate and single line do not work:
#BagA.setter,#BagA.deleter
def BagA(value):
print('cannot set or delete') #Is this possible?
I have __BagA and __BagB with underscores because I do not want it to get changed from outside.
that's not what it's for, the double underscore is a way to avoid name collisions in inheritance scenarios
that's not how it works, the double underscore just mangles names using a well-defined scheme, the double underscore does not make things private or protected, they're still completely public and visible to anyone who cares
that doesn't do anything at the module level, it's implemented at the class level
I have a getter as shown using #property decorator. But it does not work.
#property is a descriptor, it works through the attribute-resolution mechanism of classes.
Here's how you say that a symbol is "private" and shouldn't be touched in python: you prefix it with a single underscore. Then if others touch it that's their problem for being idiots or assholes.

Python: mocks in unittests

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.

pytest: how do I get the (mock) instances returned from a mocked class?

I must be tired, because surely there is an easy way to do this.
But I've read over the pytest docs and can't figure out this simple use case.
I have a little package I want to test:
class MyClass:
def __init__(self):
pass
def my_method(self, arg):
pass
def the_main_method():
m = MyClass()
m.my_method(123)
I would like to ensure that (1) an instance of MyClass is created, and that (2) my_method is called, with the proper arguments.
So here's my test:
from unittest.mock import patch
#patch('mypkg.MyClass', autospec=True)
def test_all(mocked_class):
# Call the real production code, with the class mocked.
import mypkg
mypkg.the_main_method()
# Ensure an instance of MyClass was created.
mocked_class.assert_called_once_with()
# But how do I ensure that "my_method" was called?
# I want something like mocked_class.get_returned_values() ...
I understand that each time the production code calls MyClass() the unittest framework whips up a new mocked instance.
But how do I get my hands on those instances?
I want to write something like:
the_instance.assert_called_once_with(123)
But where do I get the_instance from?
Well, to my surprise, there is only one mock instance created, no matter how many times you call the constructor (:
What I can write is:
mocked_class.return_value.my_method.assert_called_once_with(123)
The return_value does not represent one return value, though — it accumulates information for all created instances.
It's a rather abstruse approach, in my mind. I assume it was copied from some crazy Java mocking library (:
If you want to capture individual returned objects, you can use .side_effect to return whatever you want, and record it in your own list, etc.

Mock a class in Python in order to call one of its methods

I'm starting to learn Python, and along with that, I try learn how to write tests for my code. I've decided to use py.test and mock for that. I'm given a quite big and complex class, to write tests for, so for a start I decided to work on a simpler example of my own.
So, I've written a very simple class (person.py in a package called src_pkg)
class Person():
def __init__(self, name, age):
self.name = name
self.age = age
def can_do_it(self, x):
result = True if x > 5 else False
print "result: ", result
return result
What I want to do, is mock the Person class, and create an instance of the mocked class, in order to be able to call the can_do_it() method.
The reason I want to do that, is because the real class I'm working on, has a really complex constructor, and I don't want to make an instance of the class by writing something like foo = Foo(x, y, z)
So, I've written my test code (test_person.py in a package called test_pkg), which is the following:
from mock import patch
class TestPerson():
def test_can_do_it(self):
with patch('src_pck.person.Person') as Person:
person = Person.return_value
print "can he do it? :", person.can_do_it(4)
but when I run:
$ py.test -v -s test_person.py
I get the following result:
platform linux2 -- Python 2.7.5 -- py-1.4.20 -- pytest-2.5.2 -- /home/kostas/.virtualenvs/excite/bin/python
collected 1 items
test_person.py:5: TestPerson.test_can_do_it Can he do it? : <MagicMock name='Person().can_do_it()' id='37709904'>
PASSED
I would expect that the expression print "can he do it? :", person.can_do_it(4) would result to can he do it? : False. As a result, there is no point of asserting anything.
I think that when I run the test, it does not call the can_do_it() method at all! (otherwise the print statement of the method would be printed, right?)
So, what am I doing wrong?
Any help would be really appreciated.
Thank you in advance.
Patch the __init__ method using mock.patch.object:
from mock import patch
import src_pkg.person as p
class TestPerson():
def test_can_do_it(self):
with patch.object(p.Person, '__init__', lambda self: None):
person = p.Person()
print "can he do it? :", person.can_do_it(4)
A mock object has mock methods, not the real methods. The real methods may depend on having a real, fully-constructed object of the right class as self, which a mock object can't provide. If you need to test the can_do_it method, you can't use a mock Person to do it.
If can_do_it doesn't depend on having a fully-constructed self available, you can move the implementation to a module-level function or static method and have the instance method call that:
class Person(object):
...
def can_do_it(self, x):
return _can_do_it(x)
def _can_do_it(x):
result = True if x > 5 else False
print "result: ", result
return result
Then you can just test the module-level function. If you need certain bits and pieces of a Person, but you don't need to construct the whole thing, then you can just construct (or mock) the bits and pieces and have the module-level function take them as arguments.
If can_do_it depends on having a real self or most of one, you may need to construct a real Person object and call the method.

Python: Get the class, which a method belongs to

Do python class-methods have a method/member themselves, which indicates the class, they belong to?
For example ...:
# a simple global function dummy WITHOUT any class membership
def global_function():
print('global_function')
# a simple method dummy WITH a membership in a class
class Clazz:
def method():
print('Clazz.method')
global_function() # prints "global_function"
Clazz.method() # prints "Clazz.method"
# until here, everything should be clear
# define a simple replacement
def xxx():
print('xxx')
# replaces a certain function OR method with the xxx-function above
def replace_with_xxx(func, clazz = None):
if clazz:
setattr(clazz, func.__name__, xxx)
else:
func.__globals__[func.__name__] = xxx
# make all methods/functions print "xxx"
replace_with_xxx(global_function)
replace_with_xxx(Clazz.method, Clazz)
# works great:
global_function() # prints "xxx"
Clazz.method() # prints "xxx"
# OK, everything fine!
# But I would like to write something like:
replace_with_xxx(Clazz.method)
# instead of
replace_with_xxx(Clazz.method, Clazz)
# note: no second parameter Clazz!
Now my question is: How is it possible, to get all method/function calls print "xxx", WITHOUT the "clazz = None" argument in the replace_with_xxx function???
Is there something possible like:
def replace_with_xxx(func): # before it was: (func, clazz = None)
if func.has_class(): # something possible like this???
setattr(func.get_class(), func.__name__, xxx) # and this ???
else:
func.__globals__[func.__name__] = xxx
Thank you very much for reading. I hope, i could make it a little bit clear, what i want. Have a nice day! :)
I do not think this is possible and as a simple explanation why we should think about following: you can define a function and attach it to the class without any additional declarations and it will be stored as a field of the class. And you can assign the same function as a class method to 2 or more different classes.
So methods shouldn't contain any information about the class.
Clazz.method will have an attribute im_class, which will tell you what the class is.
However, if you find yourself wanting to do this, it probably means you are doing something the hard way. I don't know what you are trying to accomplish but this is a really bad way to do just about anything unless you have no other option.
For methods wrapped in #classmethod, the method will be bound and contain the reference im_self pointing to the class.

Categories

Resources