5 Easy Ways To Read JSON Input Data In Pytest

Javascript Object Notation (JSON) is arguably one of the most popular data exchange formats over the web.

Web services use serialisation to convert data from low-level data structures to JSON format that allows receiving services to easily deserialise it.

When writing Unit tests the need for testing JSON input and outputs is one of high importance.

Test data, API Responses and sometimes even config files are defined in JSON which makes it necessary to understand how to read and write to it, using Pytest.

In this article, we’ll explore 5 easy ways to read JSON data in Pytest so you can use it to validate input test data, config files, API responses and much more.

Let’s get into it.

Link To GitHub Repo

Objectives

By the end of this tutorial you should be able to:

  • Parse JSON data in Pytest using 5 different ways
  • Understand how to use Pytest fixtures and parameters to parse JSON data into your unit tests

Project Set Up

The project has the following structure

pytest-read-json-repo

Getting Started

To get started, clone the repo here, or create one by making a folder and running git init to initialise it.

Prerequisites

In this project, we’ll be using Python 3.10.10.

Create a virtual environment and install the requirements (packages) using

1
pip install -r requirements.txt

No special libraries are required here, just pytest and a lint formatter.

Now let’s look at 5 different ways to parse JSON inputs in Pytest.

Source Code

Our source code is an extremely simple example, that takes a JSON string input and calculates the birth_year from the age field.

read_json/core.py

1
2
3
4
5
6
7
8
9
10
import json  

def compute_birth_year(input_data: str):
# Parse the JSON data into a Python dictionary
data = json.loads(input_data)

# Compute birth year
birth_year = 2023 - data["age"]

return f"{data['name']} was born in {birth_year}"

Let’s look at how to test this in a few different ways.

1. Define JSON in Test

One of the easiest ways to test this is to define the input JSON in our Unit Test.

tests/unit/test_read_json.py

1
2
3
4
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

While this is easy, it offers less flexibility.

If you wish to run your test with new JSON data, we have to make changes to our test module (which is inconvenient).

2. Read An External JSON File

An interesting and convenient way to read a JSON file is to keep it separate, outside the test module itself.

This way you can make changes to it dynamically, without changing the tests themselves.

tests/unit/test_read_json.py

1
2
3
4
5
6
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

Here we’ve used the pathlib module to parse the file but you can also use the json module.

The benefit here is we decouple the input from the test module, but you’ll run into test errors if the input file is unavailable.

3. Provide JSON Data as a Fixture

Another way (and one I’m a big fan of) is to provide your input data as a Pytest fixture.

If you’re not familiar with pytest fixtures and how they work, this article provides an excellent base.

In short, fixtures are Pytest functions (often defined in conftest.py ) that can be easily used across one or more test modules and state-controlled via the scope parameter.

We define the JSON fixture

tests/unit/conftest.py

1
2
3
@pytest.fixture(scope="session")  
def input_json():
return json.dumps({"name": "Eric", "age": 32, "city": "London"})

Now we can use it within our unit test.

tests/unit/test_read_json.py

1
2
3
def test_compute_birth_year_3(input_json):  
expected = "Eric was born in 1991"
assert compute_birth_year(input_json) == expected

4. Define JSON Using Pytest Parameters

You can also make use of parameters within pytest to define test inputs.

For this, we use the @pytest.mark.parametrize marker. Let’s take a look.

tests/unit/test_read_json.py

1
2
3
4
5
6
@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

Within the marker, we define our input data and expected value, then define a list of input values (each element being a tuple).

Pytest will pass this list of input values to the test. Pretty neat!

5. Provide JSON At Runtime

The final way to parse JSON to your unit tests is to provide it at runtime, as a CLI input.

To do this, we define a couple of fixtures within conftest.py .

conftest.py

1
2
3
4
5
6
7
8
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")

We use the inbuilt parser to parse the flag --input-json to pytest, specify a default value and lastly, use that as a fixture.

We can then use it within the unit test.

tests/unit/test_read_json.py

1
2
3
@pytest.fixture  
def input_json_command_line(request):
return request.config.getoption("--input-json")

This approach although easy, doesn’t scale well especially if you need to parse multiple JSONs.

Running The Unit Test

To run the unit tests, simply run

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

pytest-read-json-run-tests

Conclusion

In this article, we looked at 5 ways to parse JSON into your unit tests.

Knowing how to parse JSON is particularly important when writing unit, integration, end-end or API testing as almost all data exchange is via JSON format.

You learnt various techniques including the use of fixtures and parameters, passing JSON via external files and the CLI.

Equipped with this knowledge, you can now efficiently parse JSON data in your Python Unit Tests.

If you have ideas for improvement or like for me to cover anything specific, please send me a message via Twitter, GitHub or Email.

Till the next time… Cheers!