You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何为Python的sample_test方法编写单元测试以捕获参数传递错误

如何避免Python可选参数位置传递错误并编写单元测试

这个坑我之前踩过好几次!当函数有多个可选参数,尤其是布尔类型和其他类型(比如字典)的可选参数相邻时,用位置参数传递很容易搞混顺序,导致参数被错误赋值,触发意料之外的逻辑分支。针对你的sample_test函数,我整理了几个解决方案,以及对应的单元测试方案:

1. 从函数定义根源杜绝错误:强制关键字参数

最有效的办法是修改函数定义,用*分隔强制后面的可选参数必须用关键字传递。这样Python会直接拒绝位置参数传递这些可选参数,从源头避免顺序错误:

def sample_test(self, param1, param2, *, optional_param1=False, optional_param2=False, optional_param3={}):
    if optional_param2:
        print("In param2")
    if optional_param3:
        print("In param3")

现在如果有人尝试用sample_test(p1, p2, False, {"key": "val"})调用,Python会立刻抛出TypeError: sample_test() takes 2 positional arguments but 4 were given,直接阻止错误的发生。

2. 编写单元测试捕获错误调用场景

如果不能修改函数定义,或者想在测试阶段验证调用的正确性,可以写单元测试来检查错误调用的行为,同时验证正确调用的结果。这里用Python标准库的unittest来实现:

import unittest
from io import StringIO
import sys

class TestSampleTest(unittest.TestCase):
    def setUp(self):
        # 捕获print的输出,方便我们验证逻辑分支是否正确触发
        self.original_stdout = sys.stdout
        sys.stdout = StringIO()

    def tearDown(self):
        # 恢复标准输出
        sys.stdout = self.original_stdout

    def test_correct_keyword_invoke(self):
        # 测试正确的关键字参数调用
        self.sample_test("param1_val", "param2_val", optional_param3={"key": "val"})
        output = sys.stdout.getvalue().strip()
        # 正确调用应该只打印"In param3"
        self.assertEqual(output, "In param3")

    def test_incorrect_positional_invoke(self):
        # 测试错误的位置参数调用,验证是否触发了错误分支
        self.sample_test("param1_val", "param2_val", False, {"key": "val"})
        output = sys.stdout.getvalue().strip()
        # 这里我们可以验证错误调用的结果,甚至主动断言失败来提示开发者
        self.assertEqual(output, "In param2")
        # 如果想强制禁止这种调用,可以添加下面的断言
        # self.fail("Avoid positional arguments for optional parameters; use keyword arguments instead")

    # 把你的sample_test函数放到测试类里方便调用
    def sample_test(self, param1, param2, optional_param1=False, optional_param2=False, optional_param3={}):
        if optional_param2:
            print("In param2")
        if optional_param3:
            print("In param3")

if __name__ == "__main__":
    unittest.main()

额外提醒:修复可变默认参数的隐藏陷阱

另外注意到你的函数用了optional_param3={}作为默认参数,这是Python的经典陷阱——可变默认参数会在函数定义时就初始化,后续每次调用如果不传这个参数,都会复用同一个字典,可能导致意外的状态残留。建议改成下面的写法:

def sample_test(self, param1, param2, optional_param1=False, optional_param2=False, optional_param3=None):
    # 如果没传optional_param3,就创建一个新的空字典
    if optional_param3 is None:
        optional_param3 = {}
    if optional_param2:
        print("In param2")
    if optional_param3:
        print("In param3")

这样每次调用时都会生成新的空字典,避免了潜在的bug。

内容的提问来源于stack exchange,提问作者Barsha Mandal

火山引擎 最新活动