【Python零基础】Python测试

news2024/9/24 3:27:22

文章目录

  • 前言
  • 一、使用pip安装pytest
    • 1.1 更新pip
    • 1.2 安装pytest
  • 二、测试函数
    • 2.1 编写测试文件
    • 2.2 运行测试
    • 2.3 测试不通过
    • 2.4 测试不通过
    • 2.4 增加新测试
  • 三、测试类
    • 3.1 断言
    • 3.2 夹具
  • 总结


前言

代码测试是程序开发中极其重要的一环,任何代码都应该经过测试才能上生产环境 。测试是为了检测代码是否能正确工作,产生和预期结果一致的输出,并且程序能否对异常或者不合理的输入给出反馈而不是直接崩溃。作为程序员,我们应该对自己的代码负责,经常测试自己的代码,在用户发现问题前找出问题,避免产生不必要的损失。

本文笔者将介绍Python中的一款测试工具 pytest,通过编写测试用例来发现和解决代码中的潜在问题。pytest不是标准的Python库,是第三方库,我们需要手动安装它。


一、使用pip安装pytest

1.1 更新pip

pip是Python提供的一个用来安装第三方包的工具,以下是windows系统的执行更新pip命令,打开cmd命令行,最好是管理员权限

python -m pip install --upgrade pip

整个命令是先运行 pip 模块,再使用 install --upgrade 更新 pip包

在这里插入图片描述
注意:windows系统在我们安装python时就自动安装了pip,linux系统则不会自动安装pip

所以linux在安装python的同时安装pip的命令如下(安装了好几个包其实)

sudo apt install python3-dev python3-pip python3-venv

在windows系统下我们可以使用如下命令更新系统中任何已安装的包:

python -m pip install --upgrade package_name

1.2 安装pytest

pip升级到最新版候就可以安装pytest了

python -m pip install --user pytest

核心命令仍然时 pip install ,–user是只为当前用户安装


二、测试函数

先来段待测试的代码,创建一个模块name_function.py
其中的代码如下

def get_formatted_name(first, last):
    """Generate a neatly formatted full name."""
    full_name = first + ' ' + last
    return full_name.title()

这是一个简单的函数 get_formatted_name() 接受用户名和姓,返回一个完整的姓名

接着我们再建立一个模块name.py,导入并使用这个函数

from name_function import get_formatted_name

while True:
    print("\nPlease tell me your name:")
    print("(enter 'q' at any time to quit)")
    f_name = input("First name: ")
    if f_name == 'q':
        break

    l_name = input("Last name: ")
    if l_name == 'q':
        break

    formatted_name = get_formatted_name(f_name, l_name)

    print("\nHello, " + formatted_name + "!")

只要我们输入的姓和名都符合要求就能得到期望的结果

在这里插入图片描述
现在的问题是,当我们修改get_formatted_name()这个函数时,我们每次都要重新运行name.py这个测试模块代码,很烦锁。pytest就提供了一种自动测试函数输出的高效方式。

2.1 编写测试文件

针对name_function.py中的函数,我们编写一个测试的模块 test_name_function.py,代码如下

import name_function


def test_first_last_name():
    """Do names like 'Janis Joplin' work?"""
    formatted_name = name_function.get_formatted_name('janis', 'joplin')
    assert formatted_name == 'Janis Joplin'

注意测试文件的命名:以test_开头,这样pytest会查找所有test_开头的文件,运行其中的测试

测试文件中待测试的函数名称也必须以test_开头,这样pytest才会测试那些需要测试的函数,后面跟的一般是待测试函数的名称

2.2 运行测试

直接运行文件test_name_function.py不会有什么结果,因为没有调用test_first_last_name()这个函数

cmd命令进入test_name_function.py所在文件位置下直接运行

pytest

这个命令如果出现不是内部命令,说明pytest没有设置全局变量,或者安装错了位置。重新执行以下命令,观察安装位置

python -m pip install --user pytest

在这里插入图片描述
按照路径找到这个Scripts文件夹

在这里插入图片描述

点进去,发现两个两个可执行文件py.test.exe,pytest.exe

在这里插入图片描述

复制粘贴到你的python安装目录下的Scripts文件夹下

在这里插入图片描述

笔者使用的工具是Pycharm,使用这款编辑器内置的终端进入(读者可以使用cmd进入到文件所在目录),输入pytest

在这里插入图片描述

2.3 测试不通过

我们对name_funtion.py中的函数get_formatted_name()稍作修改,增加一个参数middle作为中间名,再使用pytest去测试

def get_formatted_name(first, last, middle=''):
    """Generate a neatly formatted full name."""
    full_name = first + ' ' + middle + ' ' + last
    return full_name.title()

在这里插入图片描述

根据测试不通过的错误信息反馈,缺少了一个last参数,因为测试代码中只传了两个参数,默认赋值给了get_formatted_name()函数中的前两个参数first和middle。

2.4 测试不通过

上述代码的测试不通过,我们可以通过增加测试时的传参来修复,但是测试代码我们一般是不做修改的。这意味着我们编写的新代码有错误不能兼容之前的逻辑,我们应该针对被测试的函数做修改。针对middle参数我们给出默认值,并分别判断其有值和无值时的逻辑走向

def get_formatted_name(first, last, middle=''):
    """Generate a neatly formatted full name."""
    if middle:
        full_name = first + ' ' + middle + ' ' + last
    else:
        full_name = first + ' ' + last
    return full_name.title()

测试代码我们无须修改,继续使用pytest进行测试

在这里插入图片描述

2.4 增加新测试

被测试的函数get_formatted_name(),我们增加了一个可选参数middle,测试代码中仍然只有传递两个参数的测试函数test_first_last_name(),所以我们现在要在test_name_function.py中增加一个三参数的测试函数test_first_last_middle_name()

def test_first_last_middle_name():
    """Do names like 'Wolfgang Amadeus Mozart' work?"""
    formatted_name = name_function.get_formatted_name(first='wolfgang', middle='amadeus', last='mozart')
    assert formatted_name == 'Wolfgang Amadeus Mozart'

可以看到两个测试方法都成功运行通过了
在这里插入图片描述


三、测试类

前面展示的都是针对单个函数的测试,这一小节来看下编写针对类的测试。针对类的测试没问题了,说明其中的方法也都通过测试了。对类的修改没有破坏其原有的行为。

3.1 断言

断言就是程序中对某个变量进行条件判断是否成立的操作,条件成立则程序继续往下运行,否则就中断抛出异常。下面的一张表展示测试中常见的断言语句。

断言用途
assert a==b断言两个值相等
assert a!=b断言两个值不等
assert a断言a的布尔值为True
assert not a断言a的布尔值为False
assert element in list断言元素在列表中
assert element not in list断言元素不在列表中

这里列出的只是常见的断言,实际当中判断条件的代码都可以使用assert

创建模块calculator.py,代码如下

class Calculator:
    def __init__(self):
        # 初始化可以在这里添加必要的设置或变量
        pass

    def add(self, a, b):
        """返回两个数的和"""
        return a + b

    def subtract(self, a, b):
        """返回两数相减的结果"""
        return a - b

    def multiply(self, a, b):
        """返回两数相乘的结果"""
        return a * b

    def divide(self, a, b):
        """返回两数相除的结果,如果除数为0则返回None"""
        if b == 0:
            return None
        return a / b

再创建test_calculator.py测试模块,分别测试上述计算类Calculator的四个方法

from calculator import Calculator


def test_add():
    calc = Calculator()
    assert calc.add(1, 2) == 3


def test_subtract():
    calc = Calculator()
    assert calc.subtract(1, 2) == -1


def test_multiply():
    calc = Calculator()
    assert calc.multiply(1, 2) == 2


def test_divide():
    calc = Calculator()
    assert calc.divide(1, 2) == 0.5

上述测试代码针对Calculator类中的四个函数都给出了对应的测试函数,使用pytest测试下

3.2 夹具

上面的测试类中,四个测试方法我们创建了四个被测试类Calculator的实例,简单示例这么写当然没问题,但是复杂项目中类有多个测试场景就变得棘手,难道每一个测试用例都要去创建一个类实例吗?夹具(fixture)就是解决该问题的,可以创建一个共享的资源供多个测试使用。pytest中使用@pytest.fixture来装饰函数,下面稍微修改下test_calculator.py模块

import pytest
from calculator import Calculator


@pytest.fixture(scope="module")
def get_calculator():
    return Calculator()


def test_add(get_calculator):
    assert get_calculator.add(1, 2) == 3


def test_subtract(get_calculator):
    assert get_calculator.subtract(1, 2) == -1


def test_multiply(get_calculator):
    assert get_calculator.multiply(1, 2) == 2


def test_divide(get_calculator):
    assert get_calculator.divide(1, 2) == 0.5

提供一个函数获取Calculator的实例,方法上打上注解@pytest.fixture,需要导入pytest。接着每个测试方法都传入一个参数get_calculator(),即传入一个Calculator实例对象。

注意:@pytest.fixture(scope=“module”),我使用了作用域module,这样每个函数传入的get_calculator()获取的实例就是同一个。如果不适用scope,那么每个测试函数传入的都是一个新的Calculator实例。

总结

本章介绍的测试内容是软件开发中最重要的环节之一,然而大多数程序员却没有写测试代码的习惯,觉得没有必要或者只是简单的自测。这让我们写的代码就没有很可靠的保证,说来也惭愧,笔者开发年限也不短了,实际开发中也没有写测试用例的习惯。编写测试代码对于软件开发非常重要,主要原因包括以下几个方面:

  1. 保证代码质量
  • 发现错误:通过编写测试代码,可以在早期发现并修复潜在的错误和缺陷。
  • 提高可靠性:确保代码按照预期工作,减少运行时错误的可能性。
  1. 文档作用
  • 清晰说明:测试代码可以作为文档的一部分,说明代码的功能和预期行为。
  • 易于理解:新加入团队的成员可以通过测试代码快速了解系统的各个部分如何工作。
  1. 重构支持
  • 安全重构:在进行代码重构时,测试代码可以帮助验证改动后的代码仍然符合原有的功能要求。
  • 减少风险:重构过程中如果有任何问题,测试代码可以迅速定位问题所在。
  1. 持续集成
  • 自动化测试:在持续集成环境中,自动化的测试代码可以确保每次提交代码后都能及时发现问题。
  • 快速反馈:测试结果能够快速反馈给开发人员,帮助他们及时修正问题。
  1. 维护成本降低
  • 易于维护:良好的测试覆盖使得代码更容易维护,因为可以随时检查改动的影响。
  • 减少回归错误:在添加新功能或修改现有功能时,测试代码可以防止引入新的错误。
  1. 团队协作
  • 共同理解:测试代码有助于团队成员之间达成共识,确保每个人都对系统的行为有相同的理解。
  • 责任明确:测试代码可以明确指出哪些部分需要改进或修复,便于分配任务。
  1. 用户信心
  • 高质量产品:高质量的测试代码可以确保最终产品更加稳定可靠,增强用户的信任感。
  • 减少用户反馈:减少因软件缺陷导致的用户反馈和支持请求。
  1. 设计驱动开发
  • 测试驱动开发 (TDD):通过先编写测试代码再编写实现代码的方式,可以更好地设计和组织代码结构。
  • 更清晰的设计:测试代码促使开发者思考边界条件和异常情况,从而设计出更健壮的系统。

综上所述,编写测试代码不仅是保证软件质量的重要手段,还能提升开发效率、降低维护成本,并且有助于团队协作和产品的长期发展。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2093763.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

sqli-labs靶场通关攻略(五十一到五十六关)

sqli-labs-master靶场第五十一关 步骤一,尝试输入?sort1 我们发现这关可以报错注入 步骤二,爆库名 ?sort1 and updatexml(1,concat(0x7e,database(),0x7e),1)-- 步骤三,爆表名 ?sort1 and updatexml(1,concat(0x7e,(select group_conc…

数据结构:树形结构(树、堆)详解

数据结构:树形结构(树、堆)详解 一、树(一)树的性质(二)树的种类二叉树多叉树满N叉树完全N叉树 (三)二叉树的实现1、二叉树结构定义2、二叉树功能实现(1&…

数字化转型中的数据应用:挑战、机遇与追赶之路

在数字化时代的大潮中,数据已悄然从企业的边缘资源跃升为最宝贵的核心资产。然而,这场数据盛宴并未带来普遍的数据应用成熟,反而揭示了企业在数据利用上的巨大鸿沟。即便是全球500强企业,在数据应用的征途上,也仅仅是比…

秋招突击——笔试总结——8/31——京东笔试

文章目录 引言正文第一题——下一个字典序的字符个人实现 第二题——冒泡排序的变种个人实现空间复杂度比较低的版本 第三题——两人走路个人实现 总结 引言 今天京东笔试做的并不好,有很多问题的关窍都没有找到,所以在很多问题上都浪费了大量的时间&am…

JVM下篇:性能监控与调优篇-04-JVM运行时参数

文章目录 4. JVM 运行时参数4.1. JVM 参数选项4.1.1. 类型一:标准参数选项4.1.2. 类型二:-X 参数选项4.1.3. 类型三:-XX 参数选项 4.2. 添加 JVM 参数选项4.3. 常用的 JVM 参数选项4.3.1. 打印设置的 XX 选项及值4.3.2. 堆、栈、方法区等内存…

Java多线程(二)线程同步

1、线程同步问题 当多个线程同时操作同一个数据时,就会产生线程同步问题。 为了确保在任何时间点一个共享的资源只被一个线程使用,使用了“同步”。当一个线程运行到需要同步的语句后,CPU不去执行其他线程中的、可能影响当前线程中的下一句代…

记一次学习--webshell绕过(动态检测)

目录 第一种样本 代码分析 第二种样本 代码分析 题目分析 结果 不断学习&#xff0c;不断进步 快就是慢&#xff0c;慢就是快。审视自身 第一种样本 <?php class xxxd implements IteratorAggregate {public $xxx "system";public function __construct(…

C++ | Leetcode C++题解之第388题文件的最长绝对路径

题目&#xff1a; 题解&#xff1a; class Solution { public:int lengthLongestPath(string input) {int n input.size();int pos 0;int ans 0;vector<int> level(n 1);while (pos < n) {/* 检测当前文件的深度 */int depth 1;while (pos < n && in…

R语言统计分析——单因素协方差分析

参考资料&#xff1a;R语言实战【第2版】 单因素协方差分析&#xff08;ANCONA&#xff09;扩展了单因素方差分析&#xff08;ANOVA&#xff09;&#xff0c;包含一个或多个定量的协变量。下面使用multcomp包中的litter数据集进行操作&#xff1a; # 加载数据集 data(litter,p…

0-HDMI高速接口协议基础介绍

高清多媒体接口(HDMI&#xff0c;High Definition Multimedia Interface)是一种数字化视频/音频接 口技术&#xff0c;是适合影像传输的专用型数字化接口&#xff0c;其可同时传送音频和视频信号&#xff0c;同时无需在 信号传送前进行数/模或者模/数转换。从2002年HDMI发布最初…

Windows 环境nginx安装使用及目录结构详解

一、 Windows 环境nginx安装及基本使用 1、下载 nginx-1.27.1 最新的主线版本 安装 nginx/Windows&#xff0c;请下载1.27.1最新的主线版本&#xff0c; nginx 的主线分支包含所有已知的修复程序。 2、 解压缩 nginx-1.27.1 版本 nginx/Windows 作为标准控制台应用程序&#x…

YOLO | YOLO目标检测算法(分类、检测、分割)

github&#xff1a;https://github.com/MichaelBeechan CSDN&#xff1a;https://blog.csdn.net/u011344545 分类、检测、分割 思考&#xff1a;计算机视觉能够解决哪些问题&#xff1f;&#xff1f;&#xff1f;&#xff1f;分类、检测、分割 分割&#xff1a;语义分割和实例分…

SOMYO™——将“照片”转为“手绘素描”的专业级软件

一定要往下看&#xff0c;最精彩的在最后哦&#xff01; 1 关于素描的几句话 素描是西方美术的灵魂。值得为自己、亲人与好友留下一张别致的素描。 素描的定义&#xff1a;艺术家通过线条的粗细、浓淡、疏密等变化&#xff0c;试图精准地再现形态的体感、质感和动感的艺术…

轻量级进程(LWP)和线程

线程是CPU调度的基本单位 进程是承担系统资源的基本实体(进程是资源分配的基本单位) 线程并不拥有系统资源,而是共享使用进程的资源,进程的资源由系统进行分配 任何一个线程都可以创建或撤销另一个线程 多进程里&#xff0c;子进程可复制父进程的所有堆和栈的数据&#xff1b…

黑神话悟空-提高画质、防卡顿、修复等各种功能、各种CT表、各种存档、武器包、人物、装备替换等193+MOD合集

193MOD合集&#xff0c;提高画质&#xff0c;减少卡顿、修复等功能MOD各种CT表各种存档武器包、物品、人物、装备、造型替换等 具体MOD可在文件内查看 特别说明&#xff1a;3款珍品大圣套装替换初始套装MOD是不同的&#xff0c;&#xff08;其中全装备珍品大圣套装是不可以跳出…

笔记 12 : 彭老师课本第 6 章, PWM ,代码实践

&#xff08;85&#xff09; 驱动写多了&#xff0c;会发现&#xff0c;首先就是硬件的初始化&#xff0c;配置硬件。 &#xff08;86&#xff09;查看源代码组织&#xff1a; &#xff08;87&#xff09; 编译过程不变&#xff1a; &#xff08;88&#xff09; 运行同以前的步…

2024年8月总结及随笔之逝

1. 回头看 日更坚持了609天。 读《零信任网络&#xff1a;在不可信网络中构建安全系统》更新完成读《软件开发安全之道&#xff1a;概率、设计与实施》开更并持续更新 2023年至2024年8月底累计码字1463007字&#xff0c;累计日均码字2402字。 2024年8月码字109278字&#x…

全网最适合入门的面向对象编程教程:42 Python常用复合数据类型-collections容器数据类型

全网最适合入门的面向对象编程教程&#xff1a;42 Python 常用复合数据类型-collections 容器数据类型 摘要&#xff1a; 在 Python 中&#xff0c;collections 模块提供了一组高效、功能强大的容器数据类型&#xff0c;扩展了内置的基础数据类型&#xff08;如 list、tuple、…

ubuntu14.04.5出现配环境后重启进不了图形化界面解决记录

前言 这段时间给公司接了一个需要使用到linux环境进行交叉编译的工程&#xff0c;就采用了简单易操作的图形化ubuntu系统。 镜像采用的是&#xff1a;ubuntu14.04.5-desktop-amd64.iso(官网下载的&#xff09; 配置环境的过程下载了众多依赖包&#xff0c;总之就是缺啥下载啥…

Mac 安装 jdk 8详细教程

Mac 电脑上安装Jdk 8 的步骤很简单&#xff0c;不用想Windows那样需要配置环境变量PATH、JAVA_HOME。 具体方法如下&#xff1a; 首先&#xff0c;去JDK官网下载对应版本的JDK 8。 这里需要注册一个账号&#xff0c;然后&#xff0c;账号下载。 下载完后&#xff0c;得到一个…