Unable to mock class methods using unitest in python - python

module a.ClassA:
class ClassA():
def __init__(self,callingString):
print callingString
def functionInClassA(self,val):
return val
module b.ClassB:
from a.ClassA import ClassA
class ClassB():
def __init__(self,val):
self.value=val
def functionInsideClassB(self):
obj=ClassA("Calling From Class B")
value=obj.functionInClassA(self.value)
Python unittest class
import unittest
from b.ClassB import ClassB
from mock import patch, Mock, PropertyMock,mock
class Test(unittest.TestCase):
#patch('b.ClassB.ClassA',autospec = True)
def _test_sample(self,classAmock):
dummyMock=Mock()
dummyMock.functionInClassA.return_value="mocking functionInClassA"
classAmock.return_value=dummyMock
obj=ClassB("dummy_val")
obj.functionInsideClassB()
assert dummyMock.functionInClassA.assert_called_once_with("dummy_val")
The assertion fails. Where exactly am I going wrong?

You assigned to return_value twice:
classAmock.return_value=dummyMock
classAmock.return_value=Mock()
That second assignment undoes your work setting up dummyMock entirely; the new Mock instance has no functionInClassA attribute set up.
You don't need to create new mock objects; just use the default return_value attribute value:
class Test(unittest.TestCase):
#patch('b.ClassB.ClassA', autospec=True)
def test_sample(self, classAmock):
instance = classAmock.return_value
instance.functionInClassA.return_value = "mocking functionInClassA"
obj = ClassB("dummy_val")
obj.functionInsideClassB()
instance.functionInClassA.assert_called_once_with("dummy_val")
You do not need to assert the return value of assert_called_once_with() as that is always None (making your extra assert fail, always). Leave the assertion to the assert_called_once_with() method, it'll raise as needed.

Related

Python3 -unittest mocking - problem with isinstance

I have some problem with mocking and testing my function/class.
I think the easiest way to explain it will be showing some code:
module.py:
import some_module
class MyClassToTest:
def __init__():
pass
def f(self, a):
if isinstance(a, some_module.someClass):
print("true")
I want to test my module.py:
test_module.py:
import sys
from unittest import mock
sys.modules['some_module'] = mock.MagicMock() # mocking whole module
def test_my_test():
to_test = MyClassToTest()
to_test.f(5)
Of course here I will have an error:
TypeError: isinstance() arg 2 must be a type or tuple of types
because some_module was mocked.
I really need to mock the "some_module" - it's needed for some other tests.
And yes, I probably should unmock the module just for some tests or maybe mock the isinstance when I'm using it in specific function?
Do you have any idea how to process it?
You are in the right way, you've just forgot to set the object spec. Here is a fully functional example based in your question.
some_module.py
class SomeModule(object):
def method(self):
return True
module.py
import some_module
class MyClass:
def __init__(self):
pass
def f(self, a):
if isinstance(a, some_module.SomeModule):
return True
return False
test_module.py
from unittest import mock
from unittest import main, TestCase
import function
class MyClassTestCase(TestCase):
def test_myclass(self):
m = mock.MagicMock(spec=function.some_module.SomeModule)
mc = function.MyClass()
self.assertEqual(mc.f(1), False)

Mocking dependencies

I am Python newbie and trying to understand how to mock methods in UTs.
Here is my Test
test_module2.py
from module2 import A
import unittest
from unittest.mock import patch, MagicMock
class TestBulkLoad(unittest.TestCase):
#patch('simple_module.SimpleModuleClass')
def test_fun(self, a):
a.simpleFun = MagicMock(return_value=3)
testA = A()
testA.fun()
assert a.simpleFun.called
and I want to check that dependent SimpleModuleClass was mocked and invoked
module2.py
from simple_module import SimpleModuleClass
class A:
def fun(self):
print('I am from A class')
thing = SimpleModuleClass()
thing.simpleFun()
return -1
simple_module.py
class SimpleModuleClass:
def simpleFun(self):
print("I am from SimpleModuleClass")
return 0
I get AssertionError. Could you help me understand how to fix this?
a.simpleFun = MagicMock(return_value=3)
This line is only modifying the method of your mock object a (which you really should rename simpleModuleMock, since it's a mock of a SimpleModule class and not an A). It doesn't mock every instance of SimpleModule everywhere in your code, hence why an instance of SimpleModule is instantiated in A.fun() and not an instance of a mock of SimpleModule.
I would use dependency injection and pass an instance of SimpleModule to A.fun() instead of instantiating it inside of it, so that you can pass a mock. You could also make thing a public variable like so:
test_module2.py:
class TestBulkLoad(unittest.TestCase):
#patch('simple_module.SimpleModuleClass')
def test_fun(self, simpleModuleMock):
simpleModuleMock.simpleFun = MagicMock(return_value=3)
testA = A()
A.thing = simpleModuleMock
assert(testA.fun() == -1)
# assert simpleModule.simpleFun.called
assert isinstance(simpleModuleMock.simpleFun, MagicMock)
module2.py:
class A:
thing = SimpleModuleClass()
def fun(self):
print('I am from A class')
self.thing.simpleFun()
return -1
Note that there may exist better solutions with Python, but if there are, 1. I don't know of them, and 2. I doubt they're good practice.

mocking/patching the value of a computed attribute from a classmethod

I am attempting to write a test for a function which calls an object's classmethod -- this classmethod goes on to return a new instance of that class.
There are plenty of examples of patching class attributes both here on stackoverflow and elsewhere but I am having difficulty understanding how to patch attribute/value such that I can test my function. I've referred to this answer.
Essentially I am trying to patch the attribute xxxx of the instance of Foo (within myFn) so that I can test/assert the subsequent value from its call to some_other_function()
The code below is standalone a 'runnable' of the problem: I'm getting an AttributeError: Foo doesn't have the attribute 'xxxx'
import time
import unittest
from unittest.mock import patch, PropertyMock
class Foo(object):
def __init__(self, xxxx):
"""long running task"""
time.sleep(5)
self.xxxx = xxxx
#classmethod
def get(cls):
"""also a long running task"""
time.sleep(5)
xxxx = 555
return cls(xxxx)
def myFn():
v = Foo.get().xxxx
# the patched `xxxx` should be 666 at this point
return some_other_function(v)
class Test(unittest.TestCase):
#patch('__main__.Foo', autospec=True)
def test_myFn(self, mock_Foo):
with patch('__main__.Foo.xxxx', new_callable=PropertyMock, return_value=666):
x = myFn()
self.assertEqual(x, 666)
if __name__ == '__main__':
unittest.main()
Very grateful for anyone's help!
You should use the create parameter that will force the creation of the attribute if it does not exist:
def test_myFn(self):
with patch('__main__.xxxx', new_callable=PropertyMock, create=True, return_value=666):
x = myFn()
self.assertEqual(666,x)

Python unittest: Unable to mock imported functions so that conditional evaluates to False

I'm encountering a problem with unit testing in Python. Specifically, when I try to mock a function my code imports, variables assigned to the output of that function get assigned to a MagicMock object instead of the mock-function's return_value. I've been digging through the docs for python's unittest library, but am not having any luck.
The following is the code I want to test:
from production_class import function_A, function_B, function_M
class MyClass:
def do_something(self):
variable = functionB()
if variable:
do_other_stuff()
else:
do_something_else
this is what I've tried:
#mock.patch(path.to.MyClass.functionB)
#mock.patch(<other dependencies in MyClass>)
def test_do_something(self, functionB_mock):
functionB_mock.return_value = None # or False, or 'foo' or whatever.
myClass = MyClass()
myClass.do_something()
self.assertTrue(else_block_was_executed)
The issue I have is that when the test gets to variable = functionB in MyClass, the variable doesn't get set to my return value; it gets set to a MagicMock object (and so the if-statement always evaluates to True). How do I mock an imported function such that when executed, variables actually get set to the return value and not the MagicMock object itself?
We'd have to see what import path you're actually using with path.to.MyClass.functionB. When mocking objects, you don't necessarily use the path directly to where the object is located, but the one that the intepreter sees when recursively importing modules.
For example, if your test imports MyClass from myclass.py, and that file imports functionB from production_class.py, the mock path would be myclass.functionB, instead of production_class.functionB.
Then there's the issue that you need additional mocks of MyClass.do_other_stuff and MyClass.do_something_else in to check whether MyClass called the correct downstream method, based on the return value of functionB.
Here's a working example that tests both possible return values of functionB, and whether they call the correct downstream method:
myclass.py
from production_class import functionA, functionB, functionM
class MyClass:
def do_something(self):
variable = functionB()
if variable:
self.do_other_stuff()
else:
self.do_something_else()
def do_other_stuff(self):
pass
def do_something_else(self):
pass
production_class.py
import random
def functionA():
pass
def functionB():
return random.choice([True, False])
def functionM():
pass
test_myclass.py
import unittest
from unittest.mock import patch
from myclass import MyClass
class MyTest(unittest.TestCase):
#patch('myclass.functionB')
#patch('myclass.MyClass.do_something_else')
def test_do_something_calls_do_something_else(self, do_something_else_mock, functionB_mock):
functionB_mock.return_value = False
instance = MyClass()
instance.do_something()
do_something_else_mock.assert_called()
#patch('myclass.functionB')
#patch('myclass.MyClass.do_other_stuff')
def test_do_something_calls_do_other_stuff(self, do_other_stuff_mock, functionB_mock):
functionB_mock.return_value = True
instance = MyClass()
instance.do_something()
do_other_stuff_mock.assert_called()
if __name__ == '__main__':
unittest.main()
calling python test_myclass.py results in:
..
----------------------------------------------------------------------
Ran 2 tests in 0.002s
OK
What I wound up doing was changing the import statements in MyClass to import the object instead of the individual methods. I was then able to mock the object without any trouble.
More explicitly I changed MyClass to look like this:
import production_class as production_class
class MyClass:
def do_something(self):
variable = production_class.functionB()
if variable:
do_other_stuff()
else:
do_something_else
and changed my test to
#mock.patch(path.to.MyClass.production_class)
def test_do_something(self, prod_class_mock):
prod_class_mock.functionB.return_value = None
myClass = MyClass()
myClass.do_something()
self.assertTrue(else_block_was_executed)

access the current unittest.TestCase instance

I'm writing some testing utility library and may want to do the following
def assertSomething(test_case, ...):
test_case.assertEqual()
Is there a way to skip passing test_case around? e.g.
def assertSomething(...):
get_current_unittest_case().assertEqual()
AssertionError
If you just want to do some checks and fail with custom message,
raising AssertionError (via raise or assert) is the way to
go. By default, TestCase.failureException
is AssertionError, and
fail
(which internally is used by convenience methods of unittest.TestCase)
just raises it.
test_things.py:
import unittest
def check_is_zero(number):
assert number == 0, "{!r} is not 0".format(number)
def check_is_one(number):
if number != 1:
raise AssertionError("{!r} is not 1".format(number))
class NumbersTest(unittest.TestCase):
def test_one(self):
check_is_one(1)
def test_zero(self):
check_is_zero(0)
TestCase mixin
An easy and relatively readable way to add new assertions is to
make a “mixin class” that test cases will subclass. Sometimes it
is good enough.
testutils.py that contains mixin:
class ArithmeticsMixin:
def check_is_one(self, number):
self.assertEqual(number, 1)
test_thing.py, actual tests:
import unittest
import testutils
class NumbersTest(unittest.TestCase, testutils.ArithmeticsMixin):
def test_one(self):
self.check_is_one(1)
If there will be many mixin classes, use of base one may help:
import unittest
import testutils
class BaseTestCase(unittest.TestCase, testutils.ArithmeticsMixin):
"""Test case with additional methods for testing arithmetics."""
class NumbersTest(BaseTestCase):
def test_one(self):
self.check_is_one(1)
Thread local and TestCase subclass
Less readable is use of special base class,
thread local
(like global, but is aware of threads) and getter function.
testutils.py:
import unittest
import threading
_case_data = threading.local() # thread local
class ImproperlyUsed(Exception):
"""Raised if get_case is called without cooperation of BaseTestCase."""
def get_case(): # getter function
case = getattr(_case_data, "case", None)
if case is None:
raise ImproperlyUsed
return case
class BaseTestCase(unittest.TestCase): # base class
def run(self, *args, **kwargs):
_case_data.case = self
super().run(*args, **kwargs)
_case_data.case = None
def check_is_one(number):
case = get_case()
get_case().assertEqual(number, 1)
When test case is running, self (test case instance) is saved as
_case_data.case, so later inside check_is_one (or any other function
that is called from inside of test method and wants to access self)
get_case will be able to get reference to test case instance. Note
that after running _case_data.case is set to None, and if
get_case is called after that, ImproperlyUsed will be raised.
test_thing.py:
import testutils
def check_is_zero(number): # example of out-of-testutils function
testutils.get_case().assertEqual(number, 0)
class NumbersTest(testutils.BaseTestCase):
def test_one(self):
testutils.check_is_one(1)
def test_zero(self):
check_is_zero(0)
s̻̙ỵ̞̜͉͎̩s.̠͚̱̹̦̩͓_̢̬ge̡̯̳̖t̞͚̖̳f̜̪̩̪r̙̖͚̖̼͉̹a͏ṃ̡̹e̞̝̱̠̙
Finally, sys._getframe.
Let’s just h́o̞̓̐p̆̇̊̇e you don’t need it, because it is part of CPython,
not Python.
testutils.py:
import sys
import unittest
class ImproperlyUsed(Exception):
"""Raised if get_case can't get "self" TestCase instance."""
def get_case():
case = sys._getframe().f_back.f_back.f_locals.get("self")
if not isinstance(case, unittest.TestCase):
raise ImproperlyUsed
return case
def check_is_one(number):
case = get_case()
get_case().assertEqual(number, 1)
sys._getframe returns frame from the top of call stack, then few
frames below f_locals is taken, and there is self: instance of
unittest.TestCase. Like in previous implementation option, there is
sanity check, but here it is done with isinstance.
test_things.py:
import unittest
import testutils
def check_is_zero(number): # example of out-of-testutils function
testutils.get_case().assertEqual(number, 0)
class NumbersTest(unittest.TestCase):
def test_one(self):
testutils.check_is_one(1)
def test_zero(self):
check_is_zero(0)
If you just want to provide assertEqual for some new type,
take a look at addTypeEqualityFunc.

Categories

Resources