3 Simple Ways To Define Environment Variables In Pytest

When writing Python code, you’ve likely used environment variables to pass configuration or other data to your code at runtime.

Specifying environment variables in Python is easy, but when it comes to testing, things can get a bit tricky.

You need to understand variable preference, how to override them, and how to ensure your tests are isolated from the local runtime environment.

So how do you define environment variables in Pytest? Should you use a .env file, fixtures, specify them for each test?

Well, in this article you’re going to learn how to define environment variables in Pytest.

We’ll look at examples and discuss the pros and cons of each method so you can choose one that works best for your use case.

Let’s get started, shall we?

Link To GitHub Repo

Why Use Environment Variables

So what’s the deal and why should you even use environment variables?

Environment variables are a great way to pass configuration information to your code at runtime. They are easy to set, secure, and can be used across different environments.

For example, if you need to access an external value, like ACCOUNT_ID, API_ENDPOINT, or DEPLOYMENT_STAGE, you can define these as environment variables.

You’ll often see parameters like database config, API keys, or other sensitive information (encrypted) passed as environment variables.

They are typically defined in Python using the os module.

1
2
3
4
import os

os.environ["ACCOUNT_ID"] = "1234"
account_id = os.getenv("ACCOUNT_ID")

Although basic enough, let’s see how to access these in Pytest.

How To Set Environment Variables In Pytest

Let’s look at a few ways to set Environment Variables in your Unit Tests.

Define Env Vars In The Test (Basic)

The most basic and straightforward way is to define the environment variables in your test file or within the test itself.

Let’s look at an example.

tests/test_env_vars.py

1
2
3
4
5
6
7
8
9
10
11
12
import os

# Manually Define Env Variables in Test
os.environ["DEPLOYMENT_STAGE"] = "prod"
os.environ["API_ENDPOINT"] = "https://api.prod.example.com"
os.environ["ACCOUNT_ID"] = "123456789"


def test_load_env_vars():
assert os.environ["DEPLOYMENT_STAGE"] == "prod"
assert os.environ["API_ENDPOINT"] == "https://api.prod.example.com"
assert os.environ["ACCOUNT_ID"] == "123456789"

Running this,

1
pytest tests/test_env_vars.py

pytest_environment_variables_basic

While easy to understand, this method is

  • Ugly
  • Not scalable (imagine you had 100s of env variables)
  • Not reusable (imagine you had 100s of tests).

Although basic, it’s still a popular way for small scale testing.

Use The python-dotenv or pytest-dotenv Package (Better)

The python-dotenv package is a popular way to define environment variables in a .env file and load them into your code.

Similarly you can also use the pytest-dotenv package.

Let’s look at an example.

First, install the package.

1
pip install python-dotenv

Next, create a .env file in the tests directory.

tests/.env

1
2
3
DEPLOYMENT_STAGE=dev
API_ENDPOINT=https://api.dev.example.com
ACCOUNT_ID=987654321

Lastly, access the environment variables in your test.

tests/test_env_vars_env_file.py

1
2
3
4
5
6
7
8
9
10
import os
from dotenv import load_dotenv

load_dotenv() # take environment variables from .env


def test_env_vars_from_env_file():
assert os.environ["DEPLOYMENT_STAGE"] == "dev"
assert os.environ["API_ENDPOINT"] == "https://api.dev.example.com"
assert os.environ["ACCOUNT_ID"] == "987654321"

Running this,

1
pytest tests/test_env_vars_env_file.py

pytest_environment_variables_env_file

Using the python-dotenv package is a cleaner and more scalable way to define environment variables. This package can read .env files or even load environment variables from a local environment.

However, it’s tough to isolate the test environment from the local environment. For example, if you want to specify environment variables specifically for tests, you’ll need to create several .env files in different folders.

This can get messy and hard to manage. You can solve that problem with the pytest-env package.

Use The pytest-env Package (Best)

The pytest-env package is a great way to define Environment Variables within your pytest.ini or pyproject.toml config file.

If you’re not familiar with pytest-ini or config files please check out this article for a brief practical overview of the different Pytest config files.

Let’s look at an example.

First, install the package.

1
pip install pytest-env

Next, create a pytest.ini file in the tests directory.

tests/pytest.ini

1
2
3
4
5
[pytest]
env =
DEPLOYMENT_STAGE=staging
API_ENDPOINT=https://api.staging.example.com
ACCOUNT_ID=56789

Lastly, access the environment variables in your test.

tests/test_env_vars_pytest_env.py

1
2
3
4
5
6
7
import os


def test_load_env_vars_pytest_env():
assert os.environ["DEPLOYMENT_STAGE"] == "staging"
assert os.environ["API_ENDPOINT"] == "https://api.staging.example.com"
assert os.environ["ACCOUNT_ID"] == "56789"

Instead of pytest.ini, you can also define these in a pyproject.toml file.

1
2
3
4
5
[tool.pytest.ini_options]
env = [
"HOME=~/tmp",
"RUN_ENV=test",
]

The pytest.ini file also allows you to define environment variables only if not set, for example using the D: prefix.

1
2
3
4
[pytest]
env =
D:HOME=~/tmp
D:RUN_ENV=test

Important Note: When running tests, environment variables defined in pytest.ini file take precedence over a .env file or local environment during the test execution.

Running this,

1
pytest tests/test_env_vars_pytest_env.py

pytest_environment_variables_pytest_env

By far, this is the cleanest approach in my opinion. It allows you to define environment variables specifically for your tests and ensures they are isolated from the local environment, without the need to create multiple .env files.

Conclusion

In this article, you learned a few ways to define environment variables in Pytest.

You explored the most basic way, within the test itself, then moved on to using the python-dotenv package, and finally the pytest-env package.

While there is no one size fits all solution, the goal here was to present a few ways, so you can choose the one that best suits your use case.

For a personal side project, it doesn’t matter if you define them within the test itself.

But if you’re writing enterprise-level code, you must be mindful of security and best practices to ensure scalability and maintainability.

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!

Additional Reading

Example Code Used
Python Dotenv Package
Pytest Env Package
What Is pytest.ini And How To Save Time Using Pytest Config
Pytest Config Files - A Practical Guide To Good Config Management