I have a script.py
file:
# in script.py
def my_basic_function(value, c):
return c(value).words()
class BasicClass:
def __init__(self, val):
self.val = val
def words():
return self.val
and a test.py
file:
# in test.py
from mock import patch
from script import my_basic_function, BasicClass
def third_function(self,):
return "not {}".format(self.val)
def fourth_function():
return "not ponies"
def init_mock(self, val):
self.val = val
@patch('script.BasicClass.words', third_function)
@patch('script.BasicClass.__init__', init_mock)
def test_my_basic_function():
assert my_basic_function("ponies", BasicClass) == "not ponies"
that I can run using pytest test.py
from the command line successfully.
If I want to use side_effect
in my @patch
, I have to do things a little differently:
@patch('script.BasicClass.words', side_effect = fourth_function)
@patch('script.BasicClass.__init__', init_mock)
def test_my_basic_function(amock):
assert my_basic_function("ponies", BasicClass) == "not ponies"
ie, I have to:
test_my_basic_function
that I never use.fourth_function
rather than third_function
, as I cannot use any class instance variables.What is the difference between patching in these two ways?
You don't need patches for what you are doing ( Example A ). You are passing in the parameter c which you know to be the class of BasicClass so no need for a patch. You would need a patch if you introduced a function call or object initialization in the function you are testing where you don't want to actually take place.
When using @patch
we should use the kwarg side_effect
to simulate the raising of exceptions, not calling other functions. If we want to simulate the return value of a function then use kwarg return_value
. If we just want to mock a function, then we just use @patch
without any kwargs. When we use patches as a decorator we need to pass them into the function. It is true they can be unused but we should use them with mock functions such as assert_called_once
or assert_called_once_with
to ensure your patches are working as expected. Please see Example B
==============Example A==================
import unittest
def my_basic_function(value, c):
return c(value).words()
class BasicClass:
def __init__(self, val):
self.val = val
def words(self):
return self.val
class TestMyBasicFunction(unittest.TestCase):
def test_my_basic_class(self):
value = my_basic_function("jeremy", BasicClass)
self.assertEqual("jeremy", value)
def test_my_basic_class_wrong(self):
value = my_basic_function("jeremy", BasicClass)
self.assertNotEqual("w33b", value)
============Example B======================
import unittest
from unittest.mock import patch
def ensure_str(value):
try:
return str(value)
except Exception:
raise TypeError
def my_basic_function(value, c):
value = ensure_str(value)
return c(value).words()
class BasicClass:
def __init__(self, val):
self.val = val
def words(self):
return self.val
class TestMyBasicFunction(unittest.TestCase):
@patch('script.ensure_str', return_value="jeremy")
def test_return_value(self, ensure_str_mock):
value = my_basic_function("jeremy", BasicClass)
ensure_str_mock.assert_called_once_with("jeremy")
self.assertEqual("jeremy", value)
@patch('script.ensure_str')
def test_no_return_value(self, ensure_str_mock):
value = my_basic_function("jeremy", BasicClass)
self.assertEqual(ensure_str_mock(), value)
@patch('script.ensure_str', side_effect=TypeError)
def test_side_effect(self, ensure_str_mock):
with self.assertRaises(TypeError):
value = my_basic_function({'apple': 'sauce'}, BasicClass)
ensure_str_mock.assert_called_once_with({'apple': 'sauce'})
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.