Testing instance methods in Python using mock - python

I have a class similarly structured to this:
class TestClass:
def a(self):
pass
def b(self):
self.a()
I want to test if running TestClass().b() successfully calls TestClass().a():
class TestTestClass(unittest.TestCase):
def test_b(self):
with patch('test_file.TestClass') as mock:
instance = mock.return_value
TestClass().b()
instance.a.assert_called()
However, it fails because a isn't called. What am I doing wrong? I went through the mock documentation and various other guides to no avail.
Thanks!

You can use patch.object() to patch the a() method of TestClass.
E.g.
test_file.py:
class TestClass:
def a(self):
pass
def b(self):
self.a()
test_test_file.py:
import unittest
from unittest.mock import patch
from test_file import TestClass
class TestTestClass(unittest.TestCase):
def test_b(self):
with patch.object(TestClass, 'a') as mock_a:
instance = TestClass()
instance.b()
instance.a.assert_called()
mock_a.assert_called()
if __name__ == '__main__':
unittest.main()
unit test result:
⚡ coverage run /Users/dulin/workspace/github.com/mrdulin/python-codelab/src/stackoverflow/66707071/test_test_file.py && coverage report -m --include='./src/**'
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
Name Stmts Miss Cover Missing
----------------------------------------------------------------------------
src/stackoverflow/66707071/test_file.py 5 1 80% 3
src/stackoverflow/66707071/test_test_file.py 12 0 100%
----------------------------------------------------------------------------
TOTAL 17 1 94%

Related

How to Mock Instance Method in Python

Consider the following three files.
# my_class.py
class MyClass:
def __init__(self):
pass
def do_thing(self):
return 5
# main.py
from my_class import MyClass
def my_func():
instance = MyClass()
instance.do_thing()
# test_main.py
from main import my_func
from unittest.mock import patch
#patch('main.MyClass')
def test_my_func(MockMyClass):
my_func()
MockMyClass.do_thing.assert_called_once()
AssertionError: Expected 'do_thing' to have been called once. Called 0 times.
I'm instantiating a class MyClass inside a driver function my_func and calling one of the class's methods do_thing. What I'd like to do is test that when the driver function is invoked, the method of the class is called exactly once. I'm encountering an assertion error that's giving me problems.
I've read a million and one SO posts and other resources online about Python mocks, but I'm not able to figure this out. I thought the trick was that the #patch decorator patches the namespace the module is imported into, not from [Python Mocking a function from an imported module. What am I doing wrong here?
The do_thing method is an instance method of MyClass, NOT class method. You assert MockMyClass.do_thing.assert_called_once() is not correct. Here is the unit test solution:
my_class.py:
class MyClass:
def __init__(self):
pass
def do_thing(self):
return 5
main.py:
from my_class import MyClass
def my_func():
instance = MyClass()
instance.do_thing()
test_main.py:
from main import my_func
import unittest
from unittest.mock import patch
class TestMain(unittest.TestCase):
#patch('main.MyClass')
def test_my_func(self, MockMyClass):
mock_my_class_instance = MockMyClass.return_value
my_func()
mock_my_class_instance.do_thing.assert_called_once()
if __name__ == '__main__':
unittest.main()
unit test results with coverage report:
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
Name Stmts Miss Cover Missing
-----------------------------------------------------------------------
src/stackoverflow/60539392/main.py 4 0 100%
src/stackoverflow/60539392/my_class.py 5 2 60% 3, 6
src/stackoverflow/60539392/test_main.py 10 0 100%
-----------------------------------------------------------------------
TOTAL

Parameterizing tests with pytest

I am learning about parameterized tests with pyest. After following the relevant pytest documentation, I came up with this simple example:
import unittest
import pytest
#pytest.fixture(autouse=True, params=['foo', 'bar'])
def foo(request):
print('fixture')
print(request.param)
class Foo(unittest.TestCase):
def setUp(self):
print('unittest setUp()')
def test(self):
print('test')
This gives the following error:
Failed: The requested fixture has no parameter defined for the current test.
E
E Requested fixture 'foo' defined in:
E tests/fixture.py:7
Line 7 is def foo(request):.
What causes this error and how do I fix it?
The goal of fixtures is to pass objects to the test cases, but the fixture you've made doesn't return or yield anything.
Then I'm not sure you can pass objects to a unittest TestCase method, i think it may create some conflicts with the self parameter.
On the other side, it can work with a simple function :
#pytest.fixture(autouse=True, params=['foo', 'bar'])
def foo(request):
print('fixture')
print(request.param)
yield request.param
# class Foo(unittest.TestCase):
# def setUp(self):
# print('unittest setUp()')
#
# def _test(self):
# print('test')
def test_fixture(foo):
assert foo == 'foo'
>>> 1 failed, 1 passed in 0.05 seconds
# test 1 run with foo : OK
# test 2 run with bar : FAILED
EDIT :
Indeed : Why cant unittest.TestCases see my py.test fixtures?

Python mock object instantiation

Using Python 2.7, and mock library
How can I test that certain patched object has been initialized with some specific arguments using mock?
Here some sample code and pseudo-code:
unittest.py :
import mock
#mock.patch('mylib.SomeObject')
def test_mytest(self, mock_someobject):
test1 = mock_someobject.return_value
test1 = method_inside_someobject.side_effect = ['something']
mylib.method_to_test()
# How can I assert that method_to_test instanced SomeObject with certain arguments?
# I further test things with that method_inside_someobject call, no problems there...
mylib.py :
from someobjectmodule import SomeObject
def method_to_test():
obj = SomeObject(arg1=val1, arg2=val2, arg3=val3)
obj.method_inside_someobject()
So, how can I test SomeObject was instanced with arg1=val1, arg2=val2, arg3=val3?
If you replaced a class with a mock, creating an instance is just another call. Assert that the right parameters have been passed to that call, for example, with mock.assert_called_with():
mock_someobject.assert_called_with(arg1=val1, arg2=val2, arg3=val3)
To illustrate, I've updated your MCVE to a working example:
test.py:
import mock
import unittest
import mylib
class TestMyLib(unittest.TestCase):
#mock.patch('mylib.SomeObject')
def test_mytest(self, mock_someobject):
mock_instance = mock_someobject.return_value
mock_instance.method_inside_someobject.side_effect = ['something']
retval = mylib.method_to_test()
mock_someobject.assert_called_with(arg1='foo', arg2='bar', arg3='baz')
self.assertEqual(retval, 'something')
if __name__ == '__main__':
unittest.main()
mylib.py:
from someobjectmodule import SomeObject
def method_to_test():
obj = SomeObject(arg1='foo', arg2='bar', arg3='baz')
return obj.method_inside_someobject()
someobjectmodule.py:
class SomeObject(object):
def method_inside_someobject(self):
return 'The real thing'
and running the test:
$ python test.py
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK

Python nose setup/teardown class fixture method not executed for test generators

In a hobby project I intend to use nose for testing, I want to put all tests for specific classes into classes since these tests share setup and other functionality. But I can't seem to get nose to execute the setup methods inside the classes.
Here is an example class that is tested:
class mwe():
def __init__(self):
self.example = ""
def setExample(self, ex):
self.example = ex
The tests work, when I don't use classes:
from nose.tools import ok_
import mwe
exampleList = []
def setUp():
print("setup")
exampleList.append("1")
exampleList.append("2")
exampleList.append("3")
def test_Example():
print("test")
for ex in exampleList:
t = mwe.mwe()
t.setExample(ex)
yield check, t, ex
def check(e, ex):
ok_(e.example == ex)
The output is as expected:
setup
test
...
----------------------------------------------------------------------
Ran 3 tests in 0.004s
OK
When a test class is used, the setup method is not executed and therefore no tests are executed.
from nose.tools import ok_
import mwe
class TestexampleClass(object):
def __init__(self):
print("__init__")
self.exampleList = []
def setup(self):
print("setup class")
self.exampleList.append("1")
self.exampleList.append("2")
self.exampleList.append("3")
def test_ExampleClass(self):
print("test class")
for ex in self.exampleList:
t = mwe.mwe()
t.setExample(ex)
yield self.check, t, ex
def check(self, we, ex):
print("check class")
ok_(we.example == ex)
I'm fairly new to python and a newbie with nose, my question is, why is setup not executed? Where is the error in my code?
__init__
test class
----------------------------------------------------------------------
Ran 0 tests in 0.002s
OK
I will be glad for any feedback.
When I use the code from this Question on SO the setup method is executed, as I would expect it.
SOLUTION: After a lot of desperation I found the following:
Nose executes the the class level setup method before the execution of the yielded function, not when the test_* methods are called, as I expected and as is the case for other test_* methods. This obviously goes against the nose documentation:
Setup and teardown functions may be used with test generators. However, please note that setup and teardown attributes attached to the generator function will execute only once. To execute fixtures for each yielded test, attach the setup and teardown attributes to the function that is yielded, or yield a callable object instance with setup and teardown attributes.
Looking at the bug reports, I found the bug report on github.
A possible workaround is to use class level fixtures:
#classmethod
def setup_class(cls):
#do stuff
pass
Your test class needs to extend TestCase and the setup method needs to be called setUp
from unittest import TestCase
class TestUtils(TestCase):
def setUp(self):
self.x = 1
def test_something(self):
self.assertEqual(1, self.x)
which outputs
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK

How to set up a resource shared by several unit tests?

In Python, how can I have one setup (which may contain expensive function calls) for a whole set of unit tests?
Example:
import unittest
class Test1(unittest.TestCase):
def setUp(self):
print "expensive call"
def test1(self):
self.assertEqual(1, 1)
def test2(self):
self.assertEqual(1, 1)
if __name__ == "__main__":
unittest.main()
Will run the expensive call twice:
$ python unittest.py
expensive call
.expensive call
.
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
How can I change it so the expensive call is made only once and its resources accessible to all tests?
UPDATE: I'm using Python 2.6.
You can use setUpClass
import unittest
class Test(unittest.TestCase):
#classmethod
def setUpClass(cls):
print 'setUpClass'
cls.data = 123
def test_one(self):
print 'test_one'
print self.data
def test_two(self):
print 'test_two'
if __name__ == "__main__":
unittest.main()
See http://docs.python.org/library/unittest.html#unittest.TestCase.setUpClass
UPDATE:
For python 2.6, I suppose you could use class-level attributes:
class Test(unittest.TestCase):
value = result_of_some_expensive_function()
def test(self):
print self.value
That function will run once when your test is defined.

Categories

Resources