【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

相关推荐
深蓝海拓14 分钟前
Pyside6(PyQT5)中的QTableView与QSqlQueryModel、QSqlTableModel的联合使用
数据库·python·qt·pyqt
无须logic ᭄21 分钟前
CrypTen项目实践
python·机器学习·密码学·同态加密
百流34 分钟前
scala文件编译相关理解
开发语言·学习·scala
Channing Lewis34 分钟前
flask常见问答题
后端·python·flask
Channing Lewis36 分钟前
如何保护 Flask API 的安全性?
后端·python·flask
水兵没月2 小时前
钉钉群机器人设置——python版本
python·机器人·钉钉
我想学LINUX3 小时前
【2024年华为OD机试】 (A卷,100分)- 微服务的集成测试(JavaScript&Java & Python&C/C++)
java·c语言·javascript·python·华为od·微服务·集成测试
雁于飞3 小时前
c语言贪吃蛇(极简版,基本能玩)
c语言·开发语言·笔记·学习·其他·课程设计·大作业
数据小爬虫@6 小时前
深入解析:使用 Python 爬虫获取苏宁商品详情
开发语言·爬虫·python