如何为仅含print输出语句无返回值的Python函数编写单元测试
针对无返回值、仅打印输出的Python函数单元测试方案
这类输出到标准输出的函数,核心测试思路是捕获运行时的标准输出(stdout),再和预期结果做比对即可,用Python自带的测试工具就能实现,不需要额外依赖。
注意你提供的info是类成员方法(第一个参数为self,且通过self.f接收传入的文件列表),下文示例默认该方法属于FileInfo类,你可以替换成实际的类名即可。
方法1:使用标准库unittest实现(无需额外安装)
用unittest.mock.patch把标准输出重定向到缓冲对象,就能获取打印的内容:
import unittest from unittest.mock import patch import io import os import time import pwd import grp # 替换为你自己的模块导入 # from your_module import FileInfo class TestInfoMethod(unittest.TestCase): def test_single_file_output(self): # 1. 创建临时测试文件,避免依赖系统文件导致结果不稳定 test_file = "test_temp.txt" with open(test_file, "w") as f: f.write("test content") # 可选:手动设置测试文件权限,方便固定预期结果 os.chmod(test_file, 0o644) # 2. 提前计算该文件的预期输出 stat = os.stat(test_file) expected_owner = pwd.getpwuid(stat.st_uid).pw_name expected_group = grp.getgrgid(stat.st_gid).gr_name expected_per = oct(stat.st_mode)[-3:] expected_mtime = time.ctime(stat.st_mtime) # 注意print默认会加换行符,预期结果末尾要加\n expected_output = f"{test_file} is owned by: {expected_owner} , group by {expected_group} with permission {expected_per} and last modified on {expected_mtime}\n" # 3. 初始化类实例,给self.f赋值 obj = FileInfo() obj.f = [test_file] # 4. 捕获标准输出 with patch("sys.stdout", new_callable=io.StringIO) as mock_stdout: obj.info() actual_output = mock_stdout.getvalue() # 5. 比对结果 self.assertEqual(actual_output, expected_output) # 测试完成后清理临时文件 os.remove(test_file) if __name__ == "__main__": unittest.main()
方法2:使用pytest实现(写法更简洁)
pytest自带capsys fixture可以直接获取标准输出,不需要手动patch:
import pytest import os import time import pwd import grp # 替换为你自己的模块导入 # from your_module import FileInfo def test_single_file_output(capsys): # 1. 创建临时测试文件 test_file = "test_temp.txt" with open(test_file, "w") as f: f.write("test content") os.chmod(test_file, 0o644) # 2. 计算预期输出 stat = os.stat(test_file) expected_owner = pwd.getpwuid(stat.st_uid).pw_name expected_group = grp.getgrgid(stat.st_gid).gr_name expected_per = oct(stat.st_mode)[-3:] expected_mtime = time.ctime(stat.st_mtime) expected_output = f"{test_file} is owned by: {expected_owner} , group by {expected_group} with permission {expected_per} and last modified on {expected_mtime}\n" # 3. 执行方法 obj = FileInfo() obj.f = [test_file] obj.info() # 4. 读取捕获的输出并比对 captured = capsys.readouterr() assert captured.out == expected_output # 清理临时文件 os.remove(test_file)
进阶:跨环境稳定测试方案
如果需要测试不依赖当前系统的用户、用户组、时间等环境因素,可以把getpwuid、getgrgid、time.ctime这些外部依赖也mock掉,手动指定返回值,这样不管在什么环境测试结果都一致:
from unittest.mock import patch @patch("your_module.getpwuid") @patch("your_module.getgrgid") @patch("your_module.time.ctime") def test_info_with_mocked_deps(mock_ctime, mock_getgrgid, mock_getpwuid, capsys): # 手动指定所有外部依赖的返回值 mock_getpwuid.return_value.pw_name = "test_user" mock_getgrgid.return_value.gr_name = "test_group" mock_ctime.return_value = "Mon Jan 1 00:00:00 2024" # 创建临时文件并设置权限为644 test_file = "test_temp.txt" with open(test_file, "w") as f: f.write("test") os.chmod(test_file, 0o644) obj = FileInfo() obj.f = [test_file] obj.info() expected_output = "test_temp.txt is owned by: test_user , group by test_group with permission 644 and last modified on Mon Jan 1 00:00:00 2024\n" assert capsys.readouterr().out == expected_output os.remove(test_file)
其他注意事项
- 如果要测试多文件场景,给
self.f传入多个临时文件路径,把多个文件的预期输出拼接后再比对即可 - 如果要测试
self.f为空的场景,直接把self.f设为[],预期输出为空字符串即可
内容的提问来源于stack exchange,提问作者Deepak Mourya
相关产品推荐
相关产品推荐

