【Python单元测试】学习笔记2

文章目录

python单元测试学习笔记1https://blog.csdn.net/qq_42761751/article/details/141144477?spm=1001.2014.3001.5501

python单元测试学习笔记2https://blog.csdn.net/qq_42761751/article/details/141202123?spm=1001.2014.3001.5501

python单元测试学习笔记3https://blog.csdn.net/qq_42761751/article/details/141233236?spm=1001.2014.3001.5501

04. Mock

  1. 什么是Mock
  2. Mock和MagicMock
  3. 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

  1. patch能做什么
  2. patch的目标
  3. 使用patch

patch能做什么

patch可以临时用Mock对象替换一个目标(函数,方法,类)

patch的目标

patch可以替换的目标:

  1. 目标必须是可以import的
  2. 是在使用目标的地方替换而不是替换定义

使用patch

使用patch的三种方式

  1. 装饰器方式
  2. 上下文管理器方式
  3. 手动方式

装饰器方式:

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

相关推荐
编程阿峰4 小时前
Python 环境配置(二)安装jupyter、matplotlib、numpy库
开发语言·python·jupyter·numpy·matplotlib
AC赳赳老秦4 小时前
CSDN 技术社区数据采集:OpenClaw 抓取公开技术热帖,生成领域技术热点周报
java·大数据·前端·数据库·python·php·openclaw
金銀銅鐵5 小时前
[Python] 一次打开多个常用的网址
python
明如正午5 小时前
【python】Python + OpenCV 实现视频关键帧提取与智能去重
python·opencv·音视频
aqi005 小时前
15天学会AI应用开发(十八)使用LangGraph实现精确记忆功能
人工智能·python·大模型·ai编程·ai应用
swany5 小时前
同步数据中,只需要几秒钟 & milvus向量数据库不可用 dify1.16.1 升级后踩坑记录
开发语言·python·numpy
编程圈子6 小时前
电机驱动开发学习21. R3_2 双相扇区电流采样与第三相重构
驱动开发·学习·重构
Jay-r6 小时前
手势粒子特效系统 Gesture Particle FX(附源码下载)
python·ai·编程·pygame·百度云·手势控制