Pytest中5种不同的方法解析JSON数据

发布于:2025-02-27 ⋅ 阅读:(14) ⋅ 点赞:(0)

关注开源优测不迷路

大数据测试过程、策略及挑战

测试框架原理,构建成功的基石

在自动化测试工作之前,你应该知道的10条建议

在自动化测试中,重要的不是工具

JavaScript 对象表示法(JSON)可以说是网络上最流行的数据交换格式之一。


Web 服务使用序列化技术将数据从底层数据结构转换为 JSON 格式,以便接收服务能够轻松地对其进行反序列化。


在编写单元测试时,测试 JSON 输入和输出的需求至关重要。


测试数据、API 响应,有时甚至配置文件都是用 JSON 定义的,这使得使用 Pytest 理解如何读取和写入 JSON 变得十分必要。


在本文中,我们将探索在 Pytest 中读取 JSON 数据的 5 种简单方法,这样你就可以用它来验证输入的测试数据、配置文件、API 响应等等。


目标


在本文结束时,你应该能够:


  1. 使用 5 种不同的方法在 Pytest 中解析 JSON 数据。

  2. 理解如何使用 Pytest 的 fixture(夹具)和参数将 JSON 数据解析到单元测试中。


入门


在开始操作前,请按以下目录组织你的代码结构

34d2f2aa379ee9730653997dacca9a7c.png


本文中不需要特殊的库,只需要 pytest 和一个代码格式化检查工具。


现在让我们来看看在 Pytest 中解析 JSON 输入的 5 种不同方法。


源代码


我们的源代码是一个非常简单的示例,它接受一个 JSON 字符串输入,并根据 “age” 字段计算出 “birth_year”(出生年份)。


read_json/core.py


import json  def compute_birth_year(input_data: str):      # 将JSON数据解析为Python字典            data = json.loads(input_data)                  # 计算出生年份            birth_year = 2023 - data["age"]                  return f"{data['name']} was born in {birth_year}"
让我们看看如何用5种不同的方式来测试这个函数。

  1. 在测试中定义 JSON


测试这个函数最简单的方法之一是在我们的单元测试中定义输入的 JSON。


tests/unit/test_read_json.py


def test_compute_birth_year_1():  input_data = '{"name": "John", "age": 30, "city": "New York"}'              expected = "John was born in 1993"              assert compute_birth_year(input_data) == expected
虽然这种方法很简单,但灵活性较差。

如果你想用新的 JSON 数据运行测试,就必须修改测试模块(这很不方便)。


2. 读取外部 JSON 文件


一种有趣且方便的读取 JSON 文件的方法是将其单独保存,放在测试模块之外。


这样你就可以动态地对其进行修改,而无需更改测试本身。


tests/unit/test_read_json.py


def test_compute_birth_year_2():      file = pathlib.Path("tests/unit/test_data/input1.json")                  with open(file) as f:                input_data = f.read()                      expected = "Jerry was born in 1968"                  assert compute_birth_year(input_data) == expected
在这里,我们使用了 pathlib 模块来解析文件,但你也可以使用 json 模块。

这种方法的好处是我们将输入与测试模块解耦了,但如果输入文件不可用,你就会遇到测试错误。


3. 将 JSON 数据作为 fixture 提供


另一种方法(也是我非常喜欢的一种)是将输入数据作为 Pytest 的 fixture 提供。


如果你不熟悉 Pytest 的 fixture 及其工作原理,这篇文章提供了很好的基础介绍。


简而言之,fixture 是 Pytest 函数(通常在 conftest.py 中定义),可以在一个或多个测试模块中轻松使用,并通过 scope 参数进行状态控制。


我们定义 JSON 的 fixture:


tests/unit/conftest.py


@pytest.fixture(scope="session")  def input_json():       return json.dumps({        "name": "Eric",         "age": 32,         "city": "London"        })
现在我们可以在单元测试中使用它了。

tests/unit/test_read_json.py


def test_compute_birth_year_3(input_json):    expected = "Eric was born in 1991"          assert compute_birth_year(input_json) == expected
4. 使用 Pytest 参数定义 JSON

你也可以利用 Pytest 中的参数来定义测试输入。


为此,我们使用 @pytest.mark.parametrize 标记。让我们来看一下。


tests/unit/test_read_json.py


@pytest.mark.parametrize( "input_data, expected", [('{"name": "Robin", "age": 55, "city": "Los Angeles"}', "Robin was born in 1968"),])  def test_compute_birth_year_4(input_data, expected):
      assert compute_birth_year(input_data) == expected
在标记中,我们定义了输入数据和预期值,然后定义了一个输入值列表(每个元素都是一个元组)。

Pytest 会将这个输入值列表传递给测试。非常简洁!


5. 在运行时提供 JSON


将 JSON 解析到单元测试中的最后一种方法是在运行时将其作为命令行界面(CLI)输入提供。


为此,我们在 conftest.py 中定义几个 fixture。


conftest.py


def pytest_addoption(parser):      parser.addoption(    "--input-json",     action="store",     default='{"name":"Rick", "age": 50, "city": "NY"}',     help="Input JSON")        @pytest.fixture  def input_json_command_line(request):      return request.config.getoption("--input-json")
我们使用内置的解析器将 --input-json 标志解析给 Pytest,指定一个默认值,最后将其用作 fixture。

然后我们可以在单元测试中使用它。


tests/unit/test_read_json.py


@pytest.fixture  def input_json_command_line(request):      return request.config.getoption("--input-json")
这种方法虽然简单,但扩展性不好,特别是当你需要解析多个 JSON 时。

运行单元测试


要运行单元测试,只需运行:


pytest tests/unit/test_read_json.py -v -s --input-json="{'name': 'Ravi', 'age': 90, 'city': 'New Delhi'}"

596ef01a18e0a7dccdb4a1982cb520c7.png


结论


在本文中,我们研究了在单元测试中解析 JSON 的 5 种方法。


在编写单元测试、集成测试、端到端测试或 API 测试时,知道如何解析 JSON 尤为重要,因为几乎所有的数据交换都是通过 JSON 格式进行的。


你学习了各种技术,包括使用 fixture 和参数、通过外部文件和命令行传递 JSON。


有了这些知识,你现在可以在 Python 单元测试中高效地解析 JSON 数据了。