2 Mock高级用法
patch是Mock库提供的一种函数装饰器,可以创建模拟并将i传递给装饰函数
使用patch()需要明白2个主要的步骤:
- 确定使用的目标对象
什么方式使用patch()
python 提供3种方式进行使用patch()
- 装饰器修饰函数或类方法
- Context manager
- Manual start/stop
2.1 装饰器修饰
2.1.1 修饰函数
面对一个数据来源与网络请求服务,且该服务还在开发阶段,不能直接进行测试,但返回结果的结构式清楚的,那么就要针对这个返回的函数进行Patch处理
模拟的函数:
----tool.py----
def load_cheers():
return "come on!!"
def create_cheers():
result = load_cheers()
return result
进行Patch处理
import unittest
from unittest import mock
from tool import create_cheers
class GetCheerDataTest(unittest.TestCase):
@mock.patch('tool.load_cheers')
def test_get_cheer_data(self, mock_load):
mock_load.return_value = "Hello"
self.assertEqual(create_cheers(), "Hello")
if __name__ == '__main__':
unittest.main()
Patch主要是为了修饰替换多重嵌套调用的类方法或者函数,可以制定为定义域内的任意函数方法
2.1.2 修饰类方法
模拟的类方法
--------------shopping_cart.py
class Shopping(object):
__product = {}
__pay_state = ''
def has_product(self, product_name:str) -> bool:
if product_name in self.__product:
return True
else:
return False
def addProduct(self, product_name:str, num:int) -> str:
if self.has_product(product_name):
self.__product[product_name] += num
return "add successfully"
else:
self.__product[product_name] = num
return "add successfully, and init it"
进行Patch处理
import unittest
from shopping_cart import Shopping
from unittest import mock
class TestShoppingCase(unittest.TestCase):
@mock.patch('shopping_cart.Shopping.addProduct')
def test_addProduct(self, mock_load):
mock_load.return_value = 'add successfully'
self.assertEqual(Shopping.addProduct("apple"), 'add successfully')
2.2 Context manager
----total.py
def read(filename):
""" read a text file and return a list of numbers """
with open(filename) as f:
lines = f.readlines()
return [float(line.strip()) for line in lines]
def calculate_total(filename):
""" return the sum of numbers in a text file """
numbers = read(filename)
return sum(numbers)
import unittest
from unittest.mock import patch
import total
class TestTotal(unittest.TestCase):
def test_calculate_total(self):
# patch total.read() function using as the mock_read object in a context manager
with patch('total.read') as mock_read:
#assign a list of numbers to the return_value property of the mock_read object:
mock_read.return_value = [1, 2, 3]
result = total.calculate_total('')
self.assertEqual(result, 6)
2.3 Manual start/stop
import unittest
from unittest.mock import patch
import total
class TestTotal(unittest.TestCase):
def test_calculate_total(self):
# start patching start a patch by calling patch() with a target is the read() function of the total module:
patcher = patch('total.read')
# create a mock object create a mock object for the read() function:
mock_read = patcher.start()
# assign the return value
mock_read.return_value = [1, 2, 3]
# test the calculate_total call the calculate_total() and test its result.
result = total.calculate_total('')
self.assertEqual(result, 6)
# stop patching stop patching by calling the stop() method of the patcher object:
patcher.stop()