【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

相关推荐
兔C38 分钟前
微信小程序的轮播图学习报告
学习·微信小程序·小程序
海海不掉头发1 小时前
苍穹外卖-day05redis 缓存的学习
学习·缓存
黄公子学安全1 小时前
Java的基础概念(一)
java·开发语言·python
程序员一诺1 小时前
【Python使用】嘿马python高级进阶全体系教程第10篇:静态Web服务器-返回固定页面数据,1. 开发自己的静态Web服务器【附代码文档】
后端·python
小木_.2 小时前
【Python 图片下载器】一款专门为爬虫制作的图片下载器,多线程下载,速度快,支持续传/图片缩放/图片压缩/图片转换
爬虫·python·学习·分享·批量下载·图片下载器
一棵开花的树,枝芽无限靠近你2 小时前
【PPTist】组件结构设计、主题切换
前端·笔记·学习·编辑器
Jiude2 小时前
算法题题解记录——双变量问题的 “枚举右,维护左”
python·算法·面试
唐小旭2 小时前
python3.6搭建pytorch环境
人工智能·pytorch·python
犬余3 小时前
设计模式之桥接模式:抽象与实现之间的分离艺术
笔记·学习·设计模式·桥接模式
是十一月末3 小时前
Opencv之对图片的处理和运算
人工智能·python·opencv·计算机视觉