I am attempting to do something similar to the following:
import unittest
class foo:
one = 1
two = 1
class bar:
one = 2
two = 2
class my_test(unittest.TestCase):
def __init__(self, di_source):
self.di = di_source
print 'initing my_test'
def setUp(self):
print 'setting up!'
def tearDown(self):
print 'tearing down :('
def test_case_one(self):
self.assertEqual(self.di.one,1)
def test_case_two(self):
self.assertEqual(self.di.two, 2)
di_one = foo()
di_two = bar()
# called from elsewhere in my application
test_one = my_test(di_one).run()
test_one = my_test(di_two).run()
My goal is to:
Be able to call run() on a test suite
Provide a DI container at runtime to that test suite
Take advantage of the setUp and tearDown functionality provided by the unit test framework
However, it seems when I attempt to do this that the unittest framework doesn't like my constructor:
AttributeError: 'my_test' object has no attribute '_testMethodName'
Is there a better way to structure this example to avoid this problem?
How about using something like this:
This allows you to create shared resources for a single suite, pass the resource to all unittests, and then test the object with multiple methods.
'''Example using a shared resource in a unittest'''
import unittest
def callable_function():
'''Generic callable_function, this should actually be connected to an object constructor or something else''
return {'a': 3}
class MyTest(unittest.TestCase):
'''Custom unittest test case'''
def __init__(self, resource, method_name):
super(MyTest, self).__init__(method_name)
self._resource = resource
def test_getitem(self):
'''Test getting item'''
self.assertEquals(self._resource['a'], 3)
def test_setitem(self):
'''Test getting item'''
self._resource['b'] = 2
self.assertEquals(self._resource['b'], 2)
def test_mutable(self):
'''Test changes persist across tests'''
self.assertEquals(self._resource['b'], 2)
def run_suite():
'''Run complete unittest suite'''
suite = unittest.TestSuite()
item = callable_function()
suite.addTests([
MyTest(item, 'test_getitem'),
MyTest(item, 'test_setitem'),
MyTest(item, 'test_mutable'),
])
runner = unittest.TextTestRunner()
runner.run(suite)
if __name__ == '__main__':
run_suite()
EDIT: If you need to discover methods on the fly, you can do the following:
import inspect
def get_tests(cls):
return [k for k, v in cls.__dict__.items() if k.startswith('test') and inspect.ismethod(v)]
for name in get_tests(MyTest):
suite.addTest(MyTest(resource, name))
The idea is simple: override the __init__ method so it takes a resource and method name, bind the resource to the class, and initialize the TestCase as normal.
When you run the test, just use the bound resource.
Related
Is there a way to have class patches with mocked properties set in once place? Say I have the following class I want to test.
class ExampleClass
def __init__(self, specific_args):
# Do something with specific args
self.specific_args = specific_args
self.sub_component = SubComponent(...)
def example_function_double_value(self) -> float:
return SomeFunction(self.specific_args, self.sub_component.value)
and it has the following unit test where I patch out SubComponent and set SubComponent.value to return 3.
import unittest
from unittest import mock
def set_patch(patch: mock.Mock):
patch_return_value = mock.Mock()
patch_return_value.value = 3
patch.return_value = patch_return_value
#mock.patch('SubComponent_Path.SubComponent')
class ExampleUnitTest(unittest.TestCase)
def test_case1(self, patch):
set_patch(patch)
specific_args1 = # Generate specific arguments for this test case
test_class = ExampleClass(specfic_args1)
# Some assertion where I expect `subcomponent.value to be 3`
def test_case2(self, patch):
set_patch(patch)
specific_args2 = # Generate specific arguments for this test case
test_class = ExampleClass(specfic_args2)
# Some other assertion where I expect `subcomponent.value to be 3`
Is there a more elegant way to do this without needing to call that helper function at the start of each test?
Setting return_value attribute of the mock is an efficient way to do it so we don't need to call the helper function.
import unittest
from unittest import mock
#mock.patch('SubComponent_Path.SubComponent')
class ExampleUnitTest(unittest.TestCase)
def setUp(self):
self.example_class = ExampleClass()
self.mocked_sub_component = self.example_class.sub_component
self.mocked_sub_component.value.return_value = 3
def test_case1(self, patch):
self.assertEqual(self.example_class.example_function_double_value, 6)
def test_case2(self, patch):
# Some other test case where I expect `subcomponent.value to be 3`
I am writing unit test in pytest and getting error on assert_called_once_with.
I tired to use same way as been shown in the pytest documentation but seems I am missing something.
# Class which I am trying to mock. (./src/Trading.py)
class BaseTrade:
def __init__(self, name):
self.name = name
class Trade(BaseTrade):
def __init__ (self, name):
BaseTrade.__init__(self, name)
def get_balance(self, value):
# do calculation and return some value
# for demo purpose hard-coding it
return value * 10
#unit test (./unitest/test_test.py
import mock
import unittest
import sys
sys.path.append("../src")
import Trading
class TestTradeClass(unittest.TestCase):
#classmethod
def setUpClass(self):
self.expected_balance = 100
#classmethod
def tearDownClass(self):
pass
def test_trade(self):
with mock.patch.object(Trading.Trade, 'get_balance', new = lambda self, x: (x * 10) ) as mock_method:
obj = Trading.Trade("AAPL")
value = obj.get_balance(10)
assert value == 100
mock_method.assert_called_once_with(100)
Error on mock_method.assert_called_once_with(100)
AttributeError: 'function' object has no attribute 'assert_called_once_with'
I'm now of the belief you want side_effect. How is this? One file, assume test.py:
#!/usr/bin/env python
import unittest
import mock
class BaseTrade:
def __init__(self, name):
self.name = name
class Trade(BaseTrade):
def __init__(self, name):
BaseTrade.__init__(self, name)
def get_balance(self, value):
# do calculation and return some value
# for demo purpose hard-coding it
return value * 10
class TestTradeClass(unittest.TestCase):
#classmethod
def setUpClass(cls):
cls.expected_balance = 100
def test_trade(self):
# Without mock
obj = Trade("AAPL")
value = obj.get_balance(10)
assert value == 100
# With Trade.get_balance param patched
with mock.patch.object(
Trade, 'get_balance', side_effect=lambda value: value * 11
) as mock_method:
obj = Trade("AAPL")
value = obj.get_balance(10)
assert value == 110
mock_method.assert_called_once_with(10)
if __name__ == "__main__":
unittest.main()
chmod +x test.py
./test.py
Output:
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
Explanation:
Use side_effect instead of new
Combined to one file to make it easier
removing Trading.Trade
#classmethod to use cls and not self.
mock_method.assert_called_once_with(10), as side_effect cares about the value passed via obj.get_balance(10) and exists to alter the output.
Closer? If not can you clarify what you're trying to mock?
It's not easy to tell, but if Trading.Trade.get_method() is actually a vanilla function and not a method - you may need unittest.mock.create_autospec()
Are any of these of assistance?
'function' object has no attribute 'assert_called_once_with'
Python3 mock replace function with another function
It's not clear whaat Trading.Trade is.
If by chance, Trading is a class that has a self.trade = Trade(...) inside, your question would be substantially different. You'd need to get in deeper, patching Trade.get_method, then. You'd likely want to import Trade from the same module class Trading uses it (e.g. from .trading import Trading, Trade) - not from where Trade is declared from - then patch the Trade.get_method.
I am trying to test a class method which is called within an__init__ function.
class abc:
def __init__(path):
list = []
foo(path)
bar('hello') # test function bar
def foo(self, path):
# does a bunch of stuff and creates internal list
list =
def bar(self):
# does a bunch of stuff and uses list
I would like to write a test for method bar here which I guess must be called through an instance of class abc. I can mock list array for this test, but cannot understand how to avoid the call to foo().
Just mock foo method for the time of testing bar. You can use patch.object.
A full example below:
import unittest
from unittest.mock import patch
class MyClass:
def __init__(self, path):
self.list = []
self.foo(path)
self.bar('/init')
def foo(self, path):
self.list.append(path)
def bar(self, path):
self.list.insert(0, path)
class MyTestClass(unittest.TestCase):
#patch.object(MyClass, 'foo')
def test_bar_decorated(self, mock):
a = MyClass('/foo')
a.bar('/bar')
self.assertEqual(a.list, ['/bar', '/init']) # .foo() wasn't invoked
if __name__ == '__main__':
unittest.main()
Notice that, a mock is created for you and passed in as an extra argument to the decorated function (we don't use it in this test). To avoid that you can use context manager version of patch.object:
def test_bar_context_manager(self):
with patch.object(MyClass, 'foo'):
a = MyClass('/foo')
a.bar('/bar')
self.assertEqual(a.list, ['/bar', '/init']) # same behaviour
In the documentation of pytest various examples for test cases are listed. Most of them show the test of functions. But I’m missing an example of how to test classes and class methods. Let’s say we have the following class in the module cool.py we like to test:
class SuperCool(object):
def action(self, x):
return x * x
How does the according test class in tests/test_cool.py have to look?
class TestSuperCool():
def test_action(self, x):
pass
How can test_action() be used to test action()?
All you need to do to test a class method is instantiate that class, and call the method on that instance:
def test_action(self):
sc = SuperCool()
assert sc.action(1) == 1
Well, one way is to just create your object within the test method and interact with it from there:
def test_action(self, x):
o = SuperCool()
assert o.action(2) == 4
You can apparently use something like the classic setup and teardown style unittest using the methods here: http://doc.pytest.org/en/latest/xunit_setup.html
I'm not 100% sure on how they are used because the documentation for pytest is terrible.
Edit: yeah so apparently if you do something like
class TestSuperCool():
def setup(self):
self.sc = SuperCool()
...
# test using self.sc down here
I would use any fixtures only to create test environment (like database connection) or data parametrization.
If your data is relatively trivial, you can define it inside the testcase:
def test_action_without_fixtures():
sc = SuperCool()
sc.element = 'snow'
sc.melt()
assert sc.element == 'water'
Example with parametrization:
#pytest.mark.parametrize("element, expected", [('snow', 'water'), ('tin', 'solder')])
def test_action_with_parametrization(element, expected):
sc = SuperCool()
sc.element = element
sc.melt()
assert sc.element == expected
OK,
I know this is mentioned in the manual, and probably has to do with side_effect and/or return_value, but a simple, direct example will help me immensely.
I have:
class ClassToPatch():
def __init__(self, *args):
_do_some_init_stuff()
def some_func():
_do_stuff()
class UUT():
def __init__(self, *args)
resource_1 = ClassToPatch()
resource_2 = ClassToPatch()
Now, I want to unit test the UUT class, and mock the ClassToPatch. Knowing the UUT class will instantiate exactly two ClassToPatch objects, I want the Mock framework to return a new Mock object for each instantiation, so I can later assert calls on each separately.
How do I achieve this using the #patch decorator in a test case? Namely, how to fix the following code sample?
class TestCase1(unittest.TestCase):
#patch('classToPatch.ClassToPatch',autospec=True)
def test_1(self,mock1,mock2):
_assert_stuff()
Here's a quick'n'dirty example to get you going:
import mock
import unittest
class ClassToPatch():
def __init__(self, *args):
pass
def some_func(self):
return id(self)
class UUT():
def __init__(self, *args):
resource_1 = ClassToPatch()
resource_2 = ClassToPatch()
self.test_property = (resource_1.some_func(), resource_2.some_func())
class TestCase1(unittest.TestCase):
#mock.patch('__main__.ClassToPatch', autospec = True)
def test_1(self, mock1):
ctpMocks = [mock.Mock(), mock.Mock()]
ctpMocks[0].some_func.return_value = "funky"
ctpMocks[1].some_func.return_value = "monkey"
mock1.side_effect = ctpMocks
u = UUT()
self.assertEqual(u.test_property, ("funky", "monkey"))
if __name__ == '__main__':
unittest.main()
I've added test_property to UUT so that the unit test does something useful. Now, without the mock test_property should be a tuple containing the ids of the two ClassToPatch instances. But with the mock it should be the tuple: ("funky", "monkey").
I've used the side_effect property of the mock object so that a different instance of ClassToPatch is returned on each call in the UUT initialiser.
Hope this helps.
Edit: Oh, by the way, when I run the unit test I get:
.
----------------------------------------------------------------------
Ran 1 test in 0.004s
OK
Here is another version which is more generic to handle any number of instances created:
class TestUUT:
def test_init(self, mocker):
class MockedClassToPatchMeta(type):
static_instance = mocker.MagicMock(spec=ClassToPatch)
def __getattr__(cls, key):
return MockedClassToPatchMeta.static_instance.__getattr__(key)
class MockedClassToPatch(metaclass=MockedClassToPatchMeta):
original_cls = ClassToPatch
instances = []
def __new__(cls, *args, **kwargs):
MockedClassToPatch.instances.append(
mocker.MagicMock(spec=MockedClassToPatch.original_cls))
MockedClassToPatch.instances[-1].__class__ = MockedClassToPatch
return MockedClassToPatch.instances[-1]
mocker.patch(__name__ + '.ClassToPatch', new=MockedClassToPatch)
UUT()
# since your original code created two instances
assert 2 == len(MockedClassToPatch.instances)
If you need more thorough validation for each instance you can access MockedClassToPatch.instances[0] or MockedClassToPatch.instances[1].
I've also created a helper library to generate the meta class boilerplate for me. To generate the needed code for your example I wrote:
print(PytestMocker(mocked=ClassToPatch, name=__name__).mock_classes().mock_classes_static().generate())