如何使用Python和Pytest比较和测试字典列表中的特定键

问题描述 投票:0回答:2

我有一个字典项目列表,我想比较字典列表中的特定键。我正在尝试以下代码,它工作正常,但我看到代码重复。无论如何我可以优化代码吗?

我的数据结构如下

[{
        "title": "x86_64",
        "type": "info",
        "list_type": ["2016-9131", "2016-9147", "2016-9444"]

    }, {
        "title": "x_64",
        "type": "info",
        "list_type": ["2036-9131", "2026-9147", "2046-9444"],
    }
]

下面是Python代码

import json,pytest

with open('expected_resuts.json') as expected_result:
    expected_results=json.load(expected_result)

with open('actual_results.json') as actual_result:
    actual_results=json.load(actual_result)

expected_title_list=[]
expected_title_list=[]
expected_name=[]
actual_name=[]

for item in expected_results:
    expected_title_list.append(item['title'])

for item in actual_results:
    expected_title_list.append(item['title'])

for item in expected_results:
    expected_name.append(item['type'])

for item in actual_results:
    actual_name.append(item['type'])


def test_title_list():
    assert expected_title_list==expected_title_list

def test_name():
    assert actual_name==expected_name
python pytest
2个回答
1
投票

仅通过使用列表推导式就可以大大改进它。您还可以在需要它的测试中移动像

expected_vpk_list
这样的变量(以避免创建太多全局变量)。下面的例子:

import json, pytest

with open('expected_results.json') as expected_result:
    expected_results = json.load(expected_result)

with open('actual_results.json') as actual_result:
    actual_results = json.load(actual_result)

def test_vpk_list():
    expected_vpk_list = [result['vpk'] for result in expected_results]
    actual_vpk_list = [result['vpk'] for result in actual_results]
    assert actual_vpk_list == expected_vpk_list

def test_patch_title():
    expected_patch_title = [result['patchTitle'] for result in expected_results]
    actual_patch_title = [result['patchTitle'] for result in actual_results]
    assert actual_patch_title == expected_patch_title

更新: 这些测试可以通过使用parametrize来合并,如下所示:

@pytest.mark.parametrize('key', [
    'vpk',
    'patchTitle',
])
def test_key_from_results(key):
    expected_values = [result[key] for result in expected_results]
    actual_values = [result[key] for result in actual_results]
    assert expected_values == actual_values

0
投票

我最终创建了一个可以在任何地方使用的函数。

def values_match(target: dict, values: dict) -> bool:
    """
    Compares values of two dicts match for certain keys only.
    """
    return all(target.get(k, Undefined) == v for k, v in values.items())

然后一个仅用于测试:

def assert_values_match(target: dict, values: dict) -> None:
    """
    Asserts values of two dicts match for certain keys only.
    """
    if not values_match(target, values):
        raise AssertionError(
            "Values do not match!"
            "\nTarget:"
            f"\n{format_dict(target)}"
            "\nValues:"
            f"\n{format_dict(values)}"
        )

所以如果我的测试失败:

def test_values_match():
    assert_values_match({'a': 2}, {'b': 2})

我得到:

AssertionError: Values do not match!
Target:
{'a': 2}
Values:
{'b': 2}

你可能已经注意到我在上面使用了

Undefined
,这显然不是 Python 中的东西,但对于描述丢失的数据很有用,而你不能用
None
来做到这一点。

您可以像这样创建您的

Undefined
值:

class _UndefinedCls:
    def __repr__(self):
        return "Undefined"

Undefined = _UndefinedCls()

未定义在这里有两个用途:

  1. 如果缺少密钥,它可以帮助我们的函数使用更少的代码返回 False。
  2. 它可用于显式测试目标字典上是否未定义某个键。

所以这就过去了:

def test_values_match():
    assert_values_match({'a': 2}, {'a': 2, 'b': Undefined})

但这不是:

def test_values_match():
    assert_values_match({'a': 2, 'b': None}, {'a': 2, 'b': Undefined})
© www.soinside.com 2019 - 2024. All rights reserved.