Python测试入门:pytest框架从零到实战
1. 项目概述为什么是pytest如果你刚开始学Python或者已经写了一些脚本想给自己的代码加点“保险”那你迟早会碰到“测试”这个词。很多新手一听测试就头大觉得那是高级工程师才搞的玩意儿离自己很远。我以前也这么想直到有一次我花了两天写的一个数据处理脚本因为一个很傻的边界条件没处理好把一批重要数据全搞乱了又花了一天多才从备份里捞回来。那次教训让我明白写代码不写测试就像开车不系安全带平时没事一出事就是大事。那为什么在众多Python测试框架里我首推pytest给新手呢简单说它把“写测试”这件事的门槛降到了最低。你不用去记一堆复杂的类继承关系比如unittest里的TestCase也不用写很多样板代码。pytest的哲学是“约定优于配置”你用最直观的方式写几个函数它就能自动发现并运行你的测试。比如你写个函数叫test_add()pytest就知道“哦这是个测试要跑一下。”这种极低的认知负担对初学者建立测试习惯至关重要。它能让你快速获得“我写的代码是可靠的”这种正向反馈而不是在框架的复杂规则里挣扎。所以这篇内容就是带你从零开始用pytest给你的Python代码穿上“防护服”。我们会从最基础的安装、写第一个测试开始一步步深入到如何组织测试文件、使用强大的夹具fixture来管理测试数据再到处理一些常见的坑。目标不是让你成为测试专家而是让你能立刻上手写出有用、可靠的测试为你的编程之路打好一个安全、扎实的基础。2. 环境准备与第一个测试2.1 安装与验证万事开头先装包。打开你的终端Windows用CMD或PowerShellMac/Linux用Terminal输入以下命令pip install pytest通常这就够了。但为了确保万无一失特别是如果你在用虚拟环境这是个好习惯强烈建议新手也尽早养成安装后可以验证一下pytest --version如果终端显示类似pytest 7.x.x的版本信息恭喜你安装成功。如果提示“命令未找到”那可能是你的Python或pip路径没在系统环境变量里或者你需要在命令前加python -m来调用即python -m pytest --version。注意很多新手会卡在环境问题上。一个建议是对于学习和小项目可以直接用系统Python。但如果你已经开始做多个项目一定要学会使用venvPython内置或conda来创建独立的虚拟环境避免包版本冲突。这里我们先以最简单的方式继续。2.2 编写被测试的代码测试总得有个对象。我们先创建一个简单的Python文件里面放一个我们想测试的函数。用你喜欢的编辑器比如VS Code, PyCharm甚至记事本也行创建一个名为calculator.py的文件内容如下# calculator.py def add(a, b): 返回两个数的和 return a b def subtract(a, b): 返回两个数的差 return a - b def is_positive(number): 判断一个数是否为正数 return number 0这三个函数很简单但足够我们开始。它们代表了典型的“计算”和“判断”逻辑。2.3 编写并运行第一个测试现在我们来为add函数写测试。按照pytest的约定测试文件应该以test_开头或者以_test.py结尾。我们在和calculator.py同一个目录下创建一个新文件命名为test_calculator.py。注意这个命名它清晰表明了这是针对calculator的测试。在test_calculator.py里写入# test_calculator.py from calculator import add def test_add_positive_numbers(): 测试两个正数相加 result add(2, 3) assert result 5 def test_add_negative_numbers(): 测试两个负数相加 result add(-1, -4) assert result -5 def test_add_mixed_numbers(): 测试正负数相加 result add(5, -3) assert result 2看测试代码就是这么直白。导入要测的函数写一个以test_开头的函数在里面调用被测试函数然后用assert语句来断言结果是否符合预期。assert是Python的关键字意思是“断言”如果后面的表达式为True测试通过如果为False测试失败。现在打开终端导航到存放这两个文件的目录然后直接运行pytest你会看到类似这样的输出 test session starts platform darwin -- Python 3.9.0, pytest-7.0.0, pluggy-1.0.0 rootdir: /Users/yourname/projects/learning_pytest collected 3 items test_calculator.py ... [100%] 3 passed in 0.01s 太棒了三个点...表示三个测试都通过了最后一行总结“3 passed”。你的第一个测试套件成功运行了pytest自动发现了test_calculator.py文件并运行了里面所有以test_开头的函数。实操心得第一次成功运行测试会有一种奇妙的安心感。你可以故意改错一个断言比如把assert result 2改成assert result 3再跑一次pytest看看失败的报告长什么样。熟悉成功和失败的输出是调试的第一步。3. 深入理解断言与测试发现3.1 断言的艺术不仅仅是相等assert是测试的基石但它的用法远不止。pytest对原生的assert语句做了增强当断言失败时它会给出非常详细的对比信息这对调试帮助巨大。让我们扩展一下test_calculator.py为is_positive函数添加测试展示多种断言方式# test_calculator.py (新增部分) from calculator import add, is_positive # ... 之前的测试函数 ... def test_is_positive_with_positive(): 测试正数返回True assert is_positive(10) is True # 也可以写成 assert is_positive(10) True # 但 is True 对于布尔值更精确。 def test_is_positive_with_zero(): 测试0返回False assert is_positive(0) is False def test_is_positive_with_negative(): 测试负数返回False assert is_positive(-5) is False def test_add_float_numbers(): 测试浮点数相加注意精度问题 result add(0.1, 0.2) # 不要用 assert result 0.3 因为浮点数精度问题会导致失败 assert abs(result - 0.3) 1e-10 # 判断两者差的绝对值是否小于一个极小的数最后这个浮点数测试是个非常重要的知识点。计算机中浮点数的表示有精度限制0.1 0.2并不完全等于0.3。直接判断相等经常会失败。正确的做法是判断两者之差是否在一个可接受的误差范围内比如1e-10。pytest也有内置的近似相等断言pytest.approx我们后面会提到。除了相等常用的断言还有assert a ! b不相等assert x is None或assert x is not None是/不是Noneassert item in list包含关系assert 1 x 10范围判断assert not condition条件为假当断言失败时pytest会给出清晰的对比。例如如果test_add_positive_numbers中我们错误地期望236pytest会输出def test_add_positive_numbers(): result add(2, 3) assert result 6 E assert 5 6 E where 5 add(2, 3) test_calculator.py:5: AssertionError它甚至告诉你5 add(2, 3)直接把计算过程都展示出来了非常友好。3.2 pytest如何发现你的测试理解pytest的测试发现规则能让你更好地组织代码。默认情况下当你运行pytest命令时它会从当前目录开始递归地向下搜索。找特定的文件名匹配test_*.py或*_test.py的文件。在文件里找测试项以test_开头的函数。以Test开头的类并且不能有__init__方法里面的以test_开头的方法。你可以通过命令行参数控制这个行为pytest tests/只运行tests目录下的测试。pytest test_calculator.py只运行特定文件。pytest test_calculator.py::test_add_positive_numbers只运行特定文件里的特定测试函数。pytest -k “add”运行所有名称中包含“add”的测试函数名、类名。pytest -v使用详细模式会输出每个测试的名字而不是点。注意事项测试文件和测试函数的名字一定要按规矩来。我见过新手把测试文件命名为mytest.py或者函数命名为check_add()然后跑pytest发现什么都没执行一头雾水。记住test_这个前缀是“开关”没它pytest就“看不见”你的测试。4. 组织测试代码类、夹具与参数化4.1 使用测试类来分组当测试越来越多时全部堆在函数里会显得杂乱。我们可以使用类来对相关的测试进行分组。这尤其适合当你需要测试一个类Class的多个方法时或者想把针对同一功能的测试集中管理。修改test_calculator.py引入测试类# test_calculator.py from calculator import add, subtract, is_positive # 可以保留之前的独立测试函数也可以移入类中。这里我们展示两种并存。 def test_add_positive_numbers(): assert add(2, 3) 5 # 定义一个测试类类名以 Test 开头 class TestCalculator: 针对calculator模块的测试类 def test_subtract_normal(self): 测试减法基本功能 assert subtract(10, 4) 6 assert subtract(0, 0) 0 def test_subtract_negative_result(self): 测试结果为负的减法 assert subtract(3, 10) -7 def test_is_positive_edge_cases(self): 测试is_positive的边界情况 assert is_positive(0.0001) is True # 很小的正数 assert is_positive(0) is False assert is_positive(-0.0001) is False # 很小的负数运行pytest -v你会看到输出中包含了TestCalculator::test_subtract_normal这样的条目结构更清晰了。使用类的好处是你可以在类级别设置一些公共的初始化或清理工作通过setup_class/teardown_class方法或者更强大的fixture让类内的测试方法共享。4.2 核心利器Fixture夹具详解Fixture是pytest最强大、最特色的功能之一没有之一。它用来为测试提供固定的、可复用的上下文或数据比如数据库连接、临时文件、特定的配置对象等。你可以把它理解为测试的“脚手架”或“后勤保障”。为什么需要Fixture想象一下你有10个测试都需要一个临时目录来存放文件。如果没有Fixture你需要在每个测试函数里都写一遍创建和删除临时目录的代码冗长且容易出错比如忘了删除。Fixture让你可以定义一次然后在多个测试中“注入”使用。定义一个简单的FixtureFixture是使用pytest.fixture装饰器定义的函数。创建一个新文件conftest.py这是pytest的一个特殊文件名其中的fixture可以被同一目录及子目录下的所有测试文件自动使用。# conftest.py import pytest import tempfile import os pytest.fixture def temporary_file(): 创建一个临时文件并写入一些初始内容测试后自动清理。 # 创建一个临时文件 temp tempfile.NamedTemporaryFile(modew, deleteFalse, suffix.txt) temp.write(Initial content\n) temp.close() # 关闭文件以便测试代码可以打开它 yield temp.name # 将文件名提供给测试函数使用 # 测试函数执行完毕后执行清理 os.unlink(temp.name) print(fCleaned up temporary file: {temp.name})在测试中使用Fixture你只需要在测试函数的参数列表中写上fixture的函数名pytest就会自动调用它并将返回值传给测试函数。# test_fixture_demo.py def test_read_from_temporary_file(temporary_file): 测试读取临时文件的内容 with open(temporary_file, r) as f: content f.read() assert Initial content in content # 你可以在这里对文件进行读写测试 # 测试结束后conftest.py中的清理代码会自动运行删除文件。 def test_write_to_temporary_file(temporary_file): 测试向临时文件写入内容 with open(temporary_file, a) as f: f.write(New line added by test\n) with open(temporary_file, r) as f: lines f.readlines() assert len(lines) 2 assert lines[1] New line added by test\n运行pytest -v -s-s参数允许打印输出这样你就能看到print的清理信息你会发现两个测试都通过了并且都使用了同一个temporary_filefixture。每个测试运行时fixture的yield语句之前的代码设置会执行yield返回的值传给测试测试结束后yield之后的代码清理会执行。这就是典型的“设置-执行-清理”模式。实操心得conftest.py是一个魔法文件。你可以把项目通用的fixture放在项目根目录的conftest.py里把某个子目录专用的fixture放在那个子目录的conftest.py里。pytest的依赖注入系统会自动处理作用域这让管理测试资源变得异常优雅。从简单的数据对象到复杂的数据库会话都可以用fixture来管理。4.3 高效测试参数化测试我们经常需要对同一个函数用多组不同的输入输出进行测试。比如测试add函数我们想测(1,2,3),(-1,1,0),(0,0,0)等多组数据。如果为每组数据都写一个单独的测试函数代码会非常重复。pytest的pytest.mark.parametrize装饰器就是为解决这个问题而生的。它允许你定义一个测试函数然后为其指定多组参数pytest会自动生成多个测试用例并分别运行。看例子我们增强对add和subtract的测试# test_calculator.py (新增部分) import pytest # ... 之前的代码 ... # 参数化测试add函数 pytest.mark.parametrize(a, b, expected, [ (1, 2, 3), (-1, -1, -2), (0, 0, 0), (100, -50, 50), (2.5, 3.5, 6.0), ]) def test_add_parametrized(a, b, expected): 使用参数化测试多组加法数据 assert add(a, b) expected # 参数化测试subtract函数并给测试用例起名 pytest.mark.parametrize(a, b, expected, [ pytest.param(10, 5, 5, idpositive_numbers), pytest.param(5, 10, -5, idresult_negative), pytest.param(0, 0, 0, idzeros), pytest.param(-3, -7, 4, idnegative_numbers), ]) def test_subtract_parametrized(a, b, expected): 使用参数化测试多组减法数据并带有用例标识 assert subtract(a, b) expected运行pytest -v你会看到test_add_parametrized被展开了成5个独立的测试用例test_subtract_parametrized被展开了4个并且第二个因为用了pytest.param和id参数在详细输出中会有[positive_numbers]这样的标识这在测试失败时能让你快速定位是哪一组数据出了问题。参数化极大地减少了代码重复让测试数据与测试逻辑分离是编写全面测试用例的必备技能。你可以把测试数据想象成一张表格每一行就是一个测试用例而pytest.mark.parametrize就是那个帮你自动循环执行每一行的工具。5. 处理复杂场景与常见问题5.1 测试预期会抛出异常的函数不是所有函数都永远返回正常结果。有些函数在输入非法时就应该抛出异常比如ValueError,TypeError。我们也要测试这种“正确的失败”。假设我们给计算器加一个除法函数并希望除数为零时抛出ZeroDivisionError。首先在calculator.py中添加# calculator.py (新增) def divide(a, b): 返回a除以b的结果 if b 0: raise ZeroDivisionError(除数不能为零) return a / b然后在测试文件中我们使用pytest.raises上下文管理器来测试异常# test_calculator.py (新增部分) import pytest from calculator import divide def test_divide_normal(): 测试正常除法 assert divide(10, 2) 5 assert divide(9, 3) 3 def test_divide_by_zero(): 测试除数为零时抛出ZeroDivisionError with pytest.raises(ZeroDivisionError) as exc_info: divide(5, 0) # 还可以进一步检查异常信息是否符合预期 assert 除数不能为零 in str(exc_info.value) def test_divide_by_zero_wrong_exception(): 错误示例预期异常与实际抛出异常不匹配 # 这个测试会失败因为抛出的不是ValueError with pytest.raises(ValueError): divide(5, 0)pytest.raises(ExpectedException)会捕获在它代码块内抛出的异常。如果异常类型匹配测试通过如果代码块没有抛出任何异常或者抛出的异常类型不匹配测试失败。as exc_info可以让我们获取到异常对象的详细信息便于做更细致的断言。5.2 跳过Skip和条件跳过Xfail测试有时某些测试在某些条件下不应该运行。比如一个功能只在Windows上有效或者一个已知的Bug尚未修复。pytest提供了标记mark来处理这些情况。pytest.mark.skip: 无条件跳过该测试。pytest.mark.skipif: 如果条件为真则跳过。pytest.mark.xfail: 标记该测试预期会失败例如针对已知Bug的测试。如果它失败了测试结果报告为XFAIL预期失败如果它意外通过了则报告为XPASS意外通过这可能需要你关注。# test_skip_xfail.py import pytest import sys pytest.mark.skip(reason这个功能尚未实现跳过) def test_feature_not_implemented(): assert False pytest.mark.skipif(sys.version_info (3, 8), reason需要Python 3.8或更高版本) def test_feature_requires_py38(): # 假设这个功能用了Python 3.8的语法 pass # 假设我们已知在Linux系统上这个测试会失败 pytest.mark.xfail(sys.platform linux, reason已知在Linux平台有Bug #123) def test_known_bug_on_linux(): # 一些在Linux上会出问题的操作 result some_platform_specific_operation() assert result expected_value def test_normal_test(): 这个测试总会运行 assert 1 1 2运行pytest -v -rs-rs显示跳过的测试的详细信息你可以看到哪些测试被跳过了以及原因。合理使用skip和xfail可以让测试报告更清晰避免无关的“噪音”失败干扰你。5.3 测试的setup和teardown类级别与模块级别虽然Fixture是更现代和灵活的方式但pytest也支持传统的xUnit风格的setup/teardown方法有时在类中组织测试时用起来更直观。setup_method/teardown_method: 在每个测试方法前后运行。setup_class/teardown_class: 在整个测试类开始前和结束后各运行一次。setup_module/teardown_module: 在整个测试模块文件开始前和结束后各运行一次。# test_setup_teardown.py import pytest def setup_module(module): print(f\n 开始执行模块 {module.__name__} 的测试) def teardown_module(module): print(f 模块 {module.__name__} 的测试执行完毕) class TestExample: classmethod def setup_class(cls): print(f\n--- 开始执行类 {cls.__name__} 的测试) cls.shared_data 初始化数据 # 类属性所有测试方法共享 classmethod def teardown_class(cls): print(f--- 类 {cls.__name__} 的测试执行完毕) def setup_method(self, method): print(f\n 准备执行方法: {method.__name__}) self.method_data 方法级数据 def teardown_method(self, method): print(f 清理方法: {method.__name__}) def test_one(self): print(f 运行 test_one, 共享数据: {self.shared_data}, 方法数据: {self.method_data}) assert True def test_two(self): print(f 运行 test_two) assert True运行pytest -v -s test_setup_teardown.py观察打印的顺序你能清晰地看到这些钩子方法的执行层次。对于简单的资源管理比如创建一个所有测试方法共享的数据库连接setup_class/teardown_class很方便。但对于更复杂的依赖管理和资源复用Fixture仍然是更推荐的方式。6. 项目实战为一个简单应用编写测试现在我们把前面学的所有东西串起来为一个稍微真实一点的小项目写测试。假设我们有一个简单的用户注册验证模块validator.py# validator.py import re class RegistrationValidator: 用户注册信息验证器 def __init__(self): self.username_pattern re.compile(r^[a-zA-Z0-9_]{3,20}$) self.email_pattern re.compile(r^[a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,}$) def validate_username(self, username): 验证用户名3-20位仅限字母、数字、下划线 if not username: return False, 用户名不能为空 if not self.username_pattern.match(username): return False, 用户名必须是3-20位的字母、数字或下划线 return True, def validate_email(self, email): 验证邮箱格式 if not email: return False, 邮箱不能为空 if not self.email_pattern.match(email): return False, 邮箱格式不正确 return True, def validate_password(self, password, confirm_password): 验证密码非空且两次输入一致 if not password or not confirm_password: return False, 密码不能为空 if password ! confirm_password: return False, 两次输入的密码不一致 if len(password) 6: return False, 密码长度至少为6位 return True, 我们的任务是为这个验证器编写全面的测试。我们将使用Fixture来创建验证器实例使用参数化来测试多组数据并测试各种边界和错误情况。创建test_validator.py# test_validator.py import pytest from validator import RegistrationValidator # 使用Fixture提供验证器实例 pytest.fixture def validator(): 返回一个干净的RegistrationValidator实例 return RegistrationValidator() # 测试用户名验证 class TestUsernameValidation: 用户名验证测试组 # 参数化有效用户名 pytest.mark.parametrize(valid_username, [ alice, bob123, charlie_2023, a * 3, # 边界最小长度3 a * 20, # 边界最大长度20 ]) def test_valid_usernames(self, validator, valid_username): 测试有效的用户名应通过验证 is_valid, message validator.validate_username(valid_username) assert is_valid is True assert message # 成功时消息应为空 # 参数化无效用户名及预期错误信息 pytest.mark.parametrize(invalid_username, expected_error, [ (None, 用户名不能为空), (, 用户名不能为空), (ab, 用户名必须是3-20位的字母、数字或下划线), # 太短 (a * 21, 用户名必须是3-20位的字母、数字或下划线), # 太长 (john doe, 用户名必须是3-20位的字母、数字或下划线), # 包含空格 (alice!, 用户名必须是3-20位的字母、数字或下划线), # 包含特殊字符 ]) def test_invalid_usernames(self, validator, invalid_username, expected_error): 测试无效的用户名应返回False和正确的错误信息 is_valid, message validator.validate_username(invalid_username) assert is_valid is False assert expected_error in message # 检查错误信息包含预期内容 # 测试邮箱验证 pytest.mark.parametrize(email, should_be_valid, [ (testexample.com, True), (user.namedomain.co.uk, True), (, False), # 空 (invalid-email, False), # 无 (domain.com, False), # 无本地部分 (user, False), # 无域名 (user.com, False), # 域名格式错误 ]) def test_email_validation(validator, email, should_be_valid): 测试邮箱格式验证 is_valid, message validator.validate_email(email) if should_be_valid: assert is_valid is True assert message else: assert is_valid is False assert message ! # 应该有错误信息 # 测试密码验证 class TestPasswordValidation: 密码验证测试组 def test_valid_password_match(self, validator): 测试密码匹配且长度足够 is_valid, msg validator.validate_password(secure123, secure123) assert is_valid is True assert msg def test_password_mismatch(self, validator): 测试密码不匹配 is_valid, msg validator.validate_password(password1, password2) assert is_valid is False assert 两次输入的密码不一致 in msg def test_password_too_short(self, validator): 测试密码过短 is_valid, msg validator.validate_password(123, 123) assert is_valid is False assert 密码长度至少为6位 in msg def test_empty_passwords(self, validator): 测试密码为空 is_valid, msg validator.validate_password(, ) assert is_valid is False assert 密码不能为空 in msg is_valid, msg validator.validate_password(somepass, ) assert is_valid is False assert 密码不能为空 in msg运行pytest -v test_validator.py。你会看到一系列测试有条不紊地执行每个有效和无效的用例都被覆盖到了。这个测试套件不仅验证了“快乐路径”正常输入更重要的是覆盖了各种边界情况和错误输入这能极大地增强代码的健壮性。7. 调试与进阶技巧7.1 使用pdb进行测试调试测试失败了但错误信息不够清楚怎么办你可以使用Python内置的调试器pdb在测试中设置断点。pytest也提供了--pdb选项在测试失败时自动进入pdb调试环境。更常用的方式是在测试代码中直接插入import pdb; pdb.set_trace()。例如当某个测试失败时你想查看中间变量的值def test_complex_calculation(validator): result some_complex_function() import pdb; pdb.set_trace() # 程序会在这里暂停进入交互式调试 assert result expected_value运行测试时执行到这一行程序会暂停命令行会变成(Pdb)提示符。此时你可以n(next): 执行下一行。s(step): 进入函数内部。c(continue): 继续运行直到下一个断点或程序结束。p variable_name: 打印变量的值。l(list): 查看当前代码位置。q(quit): 退出调试。这是一个非常强大的线下调试工具。7.2 生成测试覆盖率报告写了这么多测试我们怎么知道测试到底覆盖了多少代码呢这就需要测试覆盖率工具。最常用的是pytest-cov。首先安装它pip install pytest-cov然后在运行pytest时加上覆盖率参数# 运行测试并计算覆盖率报告输出到终端 pytest --covvalidator test_validator.py # 生成更详细的HTML报告方便在浏览器中查看哪些行没被覆盖 pytest --covvalidator --cov-reporthtml test_validator.py运行后--covvalidator指定要计算覆盖率的模块我们的validator.py。终端会显示一个百分比。如果使用了--cov-reporthtml会生成一个htmlcov目录打开里面的index.html你可以看到每个文件的行覆盖率点击文件还能高亮显示哪些代码行被测试执行过绿色哪些没有红色。追求100%覆盖率有时不现实也没必要但覆盖率报告是一个极好的工具它能帮你发现那些完全没被测试到的“盲区”代码尤其是错误处理分支如if not username:这种。7.3 常用命令行参数与小技巧掌握一些常用的pytest命令行参数能极大提升效率pytest -x: 遇到第一个失败测试就停止。适合在快速迭代时不想等所有测试跑完。pytest --lf或pytest --last-failed: 只重新运行上次失败的测试。pytest --tbshort: 当测试失败时打印简短的追溯信息避免冗长的输出刷屏。pytest -q: 安静模式减少输出信息。pytest -m slow: 只运行标记为pytest.mark.slow的测试。你可以用pytest.mark.slow装饰那些运行很慢的集成测试平时用pytest -m “not slow”跳过它们只在需要时运行。pytest --durations10: 显示最慢的10个测试帮你定位性能瓶颈。7.4 组织大型测试项目当项目变大时测试代码也需要良好的组织目录结构通常创建一个tests目录与项目源代码分开。在tests目录下可以建立子目录如tests/unit单元测试、tests/integration集成测试、tests/fixtures存放复杂的fixture定义。my_project/ ├── src/ │ └── my_package/ │ ├── __init__.py │ ├── module1.py │ └── module2.py └── tests/ ├── unit/ │ ├── test_module1.py │ └── test_module2.py ├── integration/ │ └── test_integration.py ├── fixtures/ │ └── database.py └── conftest.py (项目根级别的fixture)conftest.py的层级你可以在任何目录下放conftest.py。低层目录如tests/unit中的fixture会覆盖高层目录如tests中同名的fixture。这提供了灵活的fixture作用域管理。测试标记使用pytest.mark.integration、pytest.mark.slow、pytest.mark.database等自定义标记来分类测试。然后可以用pytest -m integration来运行特定类别的测试。从写第一个assert语句到构建一个结构清晰、覆盖全面的测试套件pytest一路陪伴工具顺手反馈即时。它让编写测试从一项繁琐任务变成一种构建信心的实践。当你每次修改代码后能一键运行所有测试并看到一片绿色的“PASSED”时那种对代码的掌控感和安全感是任何文档都无法替代的。

相关新闻

F3闪存检测工具:3步识别扩容盘,保护你的数据安全

F3闪存检测工具:3步识别扩容盘,保护你的数据安全

F3闪存检测工具:3步识别扩容盘,保护你的数据安全 【免费下载链接】f3 F3 - Fight Flash Fraud 项目地址: https://gitcode.com/gh_mirrors/f3/f3 F3(Fight Flash Fraud)是一款专业的开源闪存检测工具,专门用于识…

2026/7/5 14:57:36阅读更多 →
11. 【C语言】表格与矩阵:多维数组

11. 【C语言】表格与矩阵:多维数组

上一篇文章我们学会了一维数组——它像一排连续的抽屉,整齐地排成一条直线。但现实中的数据往往比“一排”更复杂:课程表有行有列,棋盘有纵横坐标,图像是由像素组成的矩形网格。这时候,一维数组就有些力不从心了。 好…

2026/7/5 14:57:36阅读更多 →
10. 【C语言】把数据排成队:一维数组

10. 【C语言】把数据排成队:一维数组

上一篇我们学会了循环,程序终于可以不知疲倦地重复干活了。但这时候一个尴尬的问题浮出水面:如果我要存储一个班 50 个学生的成绩,难道要定义 score1, score2, score3 ... score50 一共 50 个变量吗? 真要这样写,别说…

2026/7/5 14:57:36阅读更多 →
Squirrel-RIFE:如何用AI补帧技术让HDR视频更流畅?5个步骤实现专业级处理

Squirrel-RIFE:如何用AI补帧技术让HDR视频更流畅?5个步骤实现专业级处理

Squirrel-RIFE:如何用AI补帧技术让HDR视频更流畅?5个步骤实现专业级处理 【免费下载链接】Squirrel-RIFE 效果更好的补帧软件,显存占用更小,是DAIN速度的10-25倍,包含抽帧处理,去除动漫卡顿感 项目地址: …

2026/7/5 21:28:18阅读更多 →
深度解析:AutoClicker - Windows桌面自动化鼠标点击工具实战指南

深度解析:AutoClicker - Windows桌面自动化鼠标点击工具实战指南

深度解析:AutoClicker - Windows桌面自动化鼠标点击工具实战指南 【免费下载链接】AutoClicker AutoClicker is a useful simple tool for automating mouse clicks. 项目地址: https://gitcode.com/gh_mirrors/au/AutoClicker 你是否曾在工作中遇到过需要重…

2026/7/5 21:28:18阅读更多 →
交叉编译 zlib

交叉编译 zlib

交叉编译 zlib 概述 zlib 被设计为一个免费的、通用的、不受法律约束的、即不受任何专利保护的无损数据压缩库,可在几乎任何计算机硬件和操作系统上使用。zlib 数据格式本身可以跨平台移植。与Unix 压缩和 GIF 图像格式中使用的 LZW 压缩方法不同,zlib 中当前使用的压缩方法…

2026/7/5 21:28:18阅读更多 →
RealSR 与 BSRGAN 等 3 种真实超分方案:原理、效果与适用场景对比

RealSR 与 BSRGAN 等 3 种真实超分方案:原理、效果与适用场景对比

RealSR、BSRGAN与DASR:真实世界超分辨率技术的深度对比与选型指南 引言:真实世界超分辨率的挑战与机遇 在理想数据集上,现代超分辨率技术已经展现出惊人的性能。但当这些技术面对真实世界图像时——那些充满复杂噪声、运动模糊和压缩伪影的日…

2026/7/5 21:28:18阅读更多 →
交叉编译 libcap

交叉编译 libcap

交叉编译 libcap 概述 由于交叉编译 systemd 依赖 libcap 库,所以需要先将 libcap 交叉编译出来,注意不是 libpcap,libpcap 是在 libcap 基础上开发的,systemd 使用的是 libcap。 libcap 属于 Linux 内核开发的一部分,源码托管在 git.kernel.org 网站。 git 网址: http…

2026/7/5 21:28:18阅读更多 →
AssetRipper终极指南:5分钟掌握Unity游戏资源提取的完整方法

AssetRipper终极指南:5分钟掌握Unity游戏资源提取的完整方法

AssetRipper终极指南:5分钟掌握Unity游戏资源提取的完整方法 【免费下载链接】AssetRipper GUI application to analyze game files 项目地址: https://gitcode.com/GitHub_Trending/as/AssetRipper 你是否曾面对Unity游戏的资源文件束手无策?那些…

2026/7/5 21:23:17阅读更多 →
从GitHub安全案例解析常见漏洞与防护实践

从GitHub安全案例解析常见漏洞与防护实践

1. 项目概述:从GitHub Trending看安全实战 最近在GitHub Trending上看到一个项目,叫 skills4/skills ,它因为一些安全漏洞案例被大家讨论。这其实是一个挺典型的场景:一个旨在展示或教授某种技能的仓库,本身却成了安…

2026/7/5 0:01:08阅读更多 →
MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

# MLT 2026启示:因果推理与概率建模驱动下一代LLM应用## 一、背景与挑战:从“黑箱预测”到“可信推理”2026年6月,第7届机器学习与趋势国际会议(MLT 2026)将在悉尼召开。会议议程中,“因果与可解释机器学习…

2026/7/5 0:01:08阅读更多 →
通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

1. 项目概述与漏洞背景最近在梳理一些历史OA系统的安全风险时,通达OA v11.6版本中的一个老漏洞又进入了我的视线。这个漏洞位于/general/bi_design/appcenter/report_bi.func.php文件中,是一个典型的SQL注入点。虽然这个漏洞的利用方式看起来并不复杂&am…

2026/7/5 0:01:08阅读更多 →
从GitHub安全案例解析常见漏洞与防护实践

从GitHub安全案例解析常见漏洞与防护实践

1. 项目概述:从GitHub Trending看安全实战 最近在GitHub Trending上看到一个项目,叫 skills4/skills ,它因为一些安全漏洞案例被大家讨论。这其实是一个挺典型的场景:一个旨在展示或教授某种技能的仓库,本身却成了安…

2026/7/5 0:01:08阅读更多 →
MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

# MLT 2026启示:因果推理与概率建模驱动下一代LLM应用## 一、背景与挑战:从“黑箱预测”到“可信推理”2026年6月,第7届机器学习与趋势国际会议(MLT 2026)将在悉尼召开。会议议程中,“因果与可解释机器学习…

2026/7/5 0:01:08阅读更多 →
通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

1. 项目概述与漏洞背景最近在梳理一些历史OA系统的安全风险时,通达OA v11.6版本中的一个老漏洞又进入了我的视线。这个漏洞位于/general/bi_design/appcenter/report_bi.func.php文件中,是一个典型的SQL注入点。虽然这个漏洞的利用方式看起来并不复杂&am…

2026/7/5 0:01:08阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/5 1:30:27阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/5 3:48:10阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/5 3:48:09阅读更多 →