如何为带有可选参数的函数编写测试

Posted

技术标签:

【中文标题】如何为带有可选参数的函数编写测试【英文标题】:How to write a test for a function with optional arguments 【发布时间】:2016-06-21 01:34:02 【问题描述】:

我想测试带有可选参数的函数调用。

这是我的代码:

list_get()
list_get(key, "city", 0)
list_get(key, 'contact_no', 2, , policy)
list_get(key, "contact_no", 0)
list_get(key, "contact_no", 1, , policy, "")
list_get(key, "contact_no", 0, 888)

由于可选参数,我无法对其进行参数化,因此我为 pytest 中的每个 api 调用编写了单独的测试函数。 我相信应该有更好的方法来测试这个。

【问题讨论】:

你不能使用一些明星魔法吗? list_get(*args) 使其与参数化测试一起使用? 【参考方案1】:

您也许可以使用* operator:

@pytest.mark.parametrize('args,expected', [
    ([], expVal0),
    ([key, "city", 0], expVal1),
    ([key, 'contact_no', 2, , policy], expVal2)
    ([key, "contact_no", 0], expVal3)
    ([key, "contact_no", 1, , policy, ""], expVal4)
    ([key, "contact_no", 0, 888], expVal5)
])
def test_list_get(args, expected):
    assert list_get(*args) == expected

【讨论】:

【参考方案2】:

我认为您所做的很好,但我建议您传递键值参数,这样您就不会混淆参数顺序。

我假设你的函数头看起来像这样:

def list_get(key=None, city=None, contact_no=None, policy=None):
    ...

在您的测试中定义您想要测试的参数组合列表:

kwargs = 'key': '..', 'city': '..', 'contact_no': '..', 'policy': '..' 
list_get(**kwargs) 

kwargs_all_default_values = 
list_get(**kwargs_all_default_values)

【讨论】:

【参考方案3】:

除了@forge 和@ezequiel-muns 的答案,我建议使用pyhamcrest 的一些糖:

import pytest
from hamcrest import assert_that, calling, is_not, raises

@pytest.mark.parametrize('func, args, kwargs', [
    [list_get, (), ],
    [list_get, (key, "city", 0), ],
    [list_get, (key, "contact_no", 1, , policy, ""), ],
    [list_get, (), 'key': key],
])
def test_func_dont_raises(func, args, kwargs):
    assert_that(calling(func).with_args(*args, **kwargs), is_not(raises(Exception)))

【讨论】:

很好,去看看这个库!【参考方案4】:

对于遇到此问题的未来读者,他们试图设置 @parameterized 测试以生成笛卡尔参数集,并且有时根本不想传递给定参数(如果可选),然后在 @ 上使用过滤器987654322@ 值会有所帮助

def function_under_test(foo="foo-default", bar="bar-default"):
    print([locals()[arg] for arg in inspect.getargspec(function_under_test).args])


@pytest.mark.parametrize("foo", [None, 1, 2])
@pytest.mark.parametrize("bar", [None, "a", "b"])
def test_optional_params(foo, bar):
    args = locals()
    filtered = k: v for k, v in args.items() if v is not None
    function_under_test(**filtered)  # <-- Notice the double star

示例运行:

PASSED   [ 11%]['foo-default', 'bar-default']
PASSED   [ 22%][1, 'bar-default']
PASSED   [ 33%][2, 'bar-default']
PASSED   [ 44%]['foo-default', 'a']
PASSED   [ 55%][1, 'a']
PASSED   [ 66%][2, 'a']
PASSED   [ 77%]['foo-default', 'b']
PASSED   [ 88%][1, 'b']
PASSED   [100%][2, 'b']

【讨论】:

以上是关于如何为带有可选参数的函数编写测试的主要内容,如果未能解决你的问题,请参考以下文章

设计模式:如何为方法添加可选参数?

PyTorch c++ 扩展中的可选张量

如何为 PyYAML 编写表示器?

PL/pgSQL 函数中的可选参数

带有可选参数的 PHP 函数

带有可选参数的 TypeScript lambda 函数