文章目录
python单元测试学习笔记1 : https://blog.csdn.net/qq_42761751/article/details/141144477?spm=1001.2014.3001.5501
python单元测试学习笔记2 :https://blog.csdn.net/qq_42761751/article/details/141202123?spm=1001.2014.3001.5501
python单元测试学习笔记3 : https://blog.csdn.net/qq_42761751/article/details/141233236?spm=1001.2014.3001.5501
04. Mock
- 什么是Mock
- Mock和MagicMock
- Mock实例
什么是Mock
Mock就是要模拟函数、方法、类的行为
Mock和MagicMock
unittest.mock模块提供了Mock和MagicMock:
Mock主要模拟指定的方法和属性
MagicMock是Mock的子类,同时模拟了很多Magic方法(len, __str__等等)
Mock实例
python
from unittest.mock import Mock
# 创建一个Mock对象
mock = Mock()
# 模拟find_person 函数,在执行测试时执行到find_person这个函数,会直接返回{"id" :1, "name":"jack"},而不是真正的去执行函数
mock.find_person.return_value = {
"id" :1,
"name":"jack"
}
# 调用find person函数
print(mock.find_person())
如果执行代码逻辑中,某一个函数不想被真的调用的话,可以使用Mock方法
05. patch
- patch能做什么
- patch的目标
- 使用patch
patch能做什么
patch可以临时用Mock对象替换一个目标(函数,方法,类)
patch的目标
patch可以替换的目标:
- 目标必须是可以import的
- 是在使用目标的地方替换而不是替换定义
使用patch
使用patch的三种方式
- 装饰器方式
- 上下文管理器方式
- 手动方式
装饰器方式:
python
import unittest
from unittest.mock import Mock,patch
from myprj.service import student_service
class TestStudentService(unittest.TestCase):
@patch("myprj.service.student_service.save_student")
@patch("myprj.service.student_service.find_student_by_id") # 把find_student_by_id函数替换成Mock对象
def test_change_name_detector(self, find_student_mock, save_student_mock):
'''参数find_student_mock与save_student_mock上述@patch是逆序的方式
'''
# setup
student = Mock(id=1, name = 'Jack')
find_student_mock.return_value = student
# Action
student_service.change_name(1, 'Tom')
# Assert
self.assertEqual('Tom', student.name)
上下文管理器方式:
python
def test_change_name_contextmanager(self):
# setup
student = Mock(id=1, name = 'Jack')
find_student_mock.return_value = student
with patch("myprj.service.student_service.find_student_by_id") as find_student_mock, \
patch("myprj.service.student_service.save_student"):
# Action
find_student_mock.return_value = student
student_service.change_name(1, 'Tom')
# Assert
self.assertEqual('Tom', student.name)
手动方式
python
@patch("myprj.service.student_service.find_student_by_id")
def test_change_name_manual(self,find_student_mock):
# setup
student = Mock(id=1, name = 'Jack')
find_student_mock.return_value = student
patcher = patch("myprj.service.student_service.save_student")
patcher.start()
# Action
student_service.change_name(1, 'Tom')
patcher.stop()
# Assert
self.assertEqual('Tom', student.name)
06.测试实例
需要被测试的代码:
python
from urllib.request import urlopen, Request
import os.path
class ProductService:
def download_img(self, url:str):
site_url = Request(url, headers={"User-Agent":"Mozilla/5.0"})
with urlopen(site_url) as web_file:
img_data = web_file.read()
if not img_data:
raise Exception(f"Error: cannot load the image from {url}")
file_name = os.path.basename(url)
with open(file_name, "wb") as file:
file.write(img_data)
return f"Download image successfully, {file_name}"
测试代码:
python
import unittest
from unittest.mock import patch, MagicMock
from product_service import ProductService
class TestProductService(unittest.TestCase):
"""
"""
def setUp(self) -> None:
self.service = ProductService()
def tearDown(self) -> None:
self.service = None
@patch("product_service.urlopen")
@patch("product_service.Request.__new__")
def test_download_img_with_excertion(self, request_mock, urlopen_mock):
# Setup
url = "http://www.google.com/a.jpg"
urlopen_return_mock = MagicMock()
webfile_mock = MagicMock()
urlopen_mock.return_value = urlopen_return_mock
urlopen_return_mock.__enter__.return_value = webfile_mock
webfile_mock.read.return_value = None
with self.assertRaises(Exception):
# Action
self.service.download_img(url)
@patch("builtins.open")
@patch("os.path.basename")
@patch("product_service.urlopen")
@patch("product_service.Request.__new__")
def test_download_img_with_success(self, request_mock, urlopen_mock, basename_mock, open_mock):
# Setup
url = "http://www.google.com/a.jpg"
urlopen_return_mock = MagicMock()
webfile_mock = MagicMock()
urlopen_mock.return_value = urlopen_return_mock
urlopen_return_mock.__enter__.return_value = webfile_mock
webfile_mock.read.return_value = "not none"
basename_mock.return_value = "fff"
# Action
result = self.service.download_img(url)
self.assertEqual("Download image successfully, fff", result)
07.覆盖率测试
测试覆盖率统计的是被测试代码在单元测试过程中有多少代码被执行到了, 覆盖率=执行到的代码行数/代码总行数
相关命令行:
统计测试覆盖率:
bash
python -m coverage run -m unittest
查看覆盖率报告:
bash
python -m coverage report
生成html格式的覆盖率报告:(在htmlcov中index.html,点击每个测试文件可以查看具体哪一行代码没有被执行到)
bash
python -m coverage html
08. PyTest框架
本文参考:
https://www.bilibili.com/video/BV1S14y1u7FL/?p=7\&spm_id_from=pageDriver