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

文章目录

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

  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

相关推荐
“AI国潮设计-小江”7 小时前
【AIGC实战】Python+SDXL批量生成“潮汕英歌舞不倒翁”IP | 角色一致性与多场景融合方案,附完整代码
开发语言·人工智能·python·prompt·aigc
Linux_cy7 小时前
服务器管理工具哪个好用?我用了七八个
运维·服务器·javascript·python·ssh·面板·gmssh
MoRanzhi12037 小时前
第6篇(下)· 使用 PyQt5 实现 2048 高性能计算版:统一运行控制与跨模式安全交接
python·pyqt·进程管理·状态机·软件架构·并发控制·数据一致性
code tsunami7 小时前
【无标题】
开发语言·python
CodeGL7 小时前
10、Python基础之进程和线程
开发语言·python
Young Doro8 小时前
独立性检测学习任务
人工智能·学习·数据挖掘
TechWayfarer9 小时前
PHP漏洞被利用,怎么揪出攻击IP?
开发语言·python·tcp/ip·网络安全·php
2601_967980119 小时前
Python列表操作方法详解
python·数据类型·修改·列表操作·功能汇总
卡卡~~10 小时前
“101计划”核心课程实践教材《数据实验结构指导-C++语言版》题目集
开发语言·c++·学习·算法
Patrick在香港10 小时前
台风在变少,来香港的没有
python·数据分析·香港·开放数据·热带气旋