Before I start executing the tests in my Python project, I read some environment variables and set some variables with these values read. My tests will run on the desired environment based on these values read.
For eg: Let's say the environment variables are called ENV_NAME
and ENV_NUMBER
Now, I would like to run the tests using py.test.
If I hard code these environment variables, for eg: ENV_NAME = 'staging', ENV_NUMBER = '5'
in my code and then run the tests by executing the py.test command at the root of the project directory, all the tests run successfully.
But, I don't want to hardcode these values. Is there a way, I can send these environment variables as command line arguments for py.test?
I was thinking more in the lines of
py.test -ENV_NAME='staging' -ENV_NUMBER='5'.
But, this is not working.
Using pytest-env plugin We can use this plugin to set environment variables that don't really matter to the function implementations.
Another alternative is to use the pytest-env plugin. It can be configured like so:
[pytest]
env =
HOME=~/tmp
D:RUN_ENV=test
the D:
prefix allows setting a default value, and not override existing variables passed to py.test
.
Note: you can explicitly run pytest with a custom config, if you only sometimes need to run a specialized environment set up:
pytest -c custom_pytest.ini
If you use PyCharm vs pytest-dotenv, this may be helpful
In addition to other answers. There is an option to overwrite pytest_generate_tests
in conftest.py
and set ENV variables there.
For example, add following into conftest.py
:
import os
def pytest_generate_tests(metafunc):
os.environ['TEST_NAME'] = 'My super test name| Python version {}'.format(python_version)
This code will allow you to grab TEST_NAME
ENV variable in your tests application. Also you could make a fixture:
import os
import pytest
@pytest.fixture
def the_name():
return os.environ.get('TEST_NAME')
Also, this ENV variable will be available in your application.
I finally found the answer i was looking for.
we can set the environment variables like this before running tests using py.test
ENV_NAME='staging' ENV_NUMBER='5' py.test
import os
# success.py
def hello_world():
return os.environ["HELLO"]
# fail.py
global_ref = os.environ["HELLO"] # KeyError occurs this line because getting environment variable before monkeypatching
def hello_world():
return global_ref
# test.py
def test_hello_world(monkeypatch):
# Setup
envs = {
'HELLO': 'world'
}
monkeypatch.setattr(os, 'environ', envs)
# Test
result = hello_world()
# Verify
assert(result == 'world')
[Run]
-> [Edit Configuration]
-> [Defaults]
-> [py.tests]
-> [Environment Variables]
There are few ways you can achieve this
If you dont want to use the environment variable , you can use pytest addoptions as https://docs.pytest.org/en/latest/example/simple.html
You can write a wrapper script like this to call enviornment variables
import os
import py
env_name = os.environ["ENV_NAME"]
env_no = os.environ["ENV_NUMBER"]
pytest_args=(env_name,env_no)
pytest.main('-s' ,pytest_args,test_file.py)
in test_file.py you can use
env_n, env_n = pytest.config.getoption('pytest_args')
on command line you can use it as
py.test --testdata ="ENV_NAME:staging,ENV_NUMBER:5"
You can use in your test file
pytest_params = pytest.config.getoption('testdata')
params = pytest_params.split(":")
param_dict = dict(params[i:i+2] for i in range(0,len(params),2))
env_name = param_dict["ENV_Name"]
Following the idea provided by @tutuDajuju using pytest-env - an alternative would be to write a custom plugin leveraging pytest_load_initial_conftests. Might be useful especially when you don't want or can't install external dependencies.
Here's a quick example:
Project structure
.
├── __init__.py
├── pytest.ini
├── script.py
└── tests
├── __init__.py
├── plugins
│ ├── __init__.py
│ └── env_vars.py
└── test_script.py
script.py
import os
FOOBAR = os.environ.get("FOOBAR")
def foobar():
return FOOBAR
test_script.py
from script import foobar
def test_foobar():
assert foobar() == "foobar"
pytest.ini
[pytest]
addopts = -p tests.plugins.env_vars
env_vars.py
import os
import pytest
@pytest.hookimpl(tryfirst=True)
def pytest_load_initial_conftests(args, early_config, parser):
os.environ["FOOBAR"] = "foobar"
Example run:
$ python -m pytest tests -v
========= test session starts =========
platform darwin -- Python 3.8.1, pytest-5.4.1, py-1.8.1, pluggy-0.13.1 --
rootdir: /Users/user/pytest_plugins, inifile: pytest.ini
collected 1 item
tests/test_script.py::test_foobar PASSED [100%]
========= 1 passed in 0.01s =========
Run export
inside a subshell (enclosing parenthesis) not to mess up local environment. Supply export with parameters from .env
file.
(export $(xargs < .env); pytest -svvvx api)
Similar to bad_coder had mentioned, you can do:
# test.py
def test_hello_world(monkeypatch):
# Setup
monkeypatch.setenv('HELLO', 'world')
# Test
result = hello_world()
# Verify
assert(result == 'world')
I needed to create a pytest.ini
file and pass the environment variables to the pytest
command. E.g:
In the pytest.ini file I set an empty value because it is overwritten by whatever you pass to the command line command:
[pytest]
MY_ENV_VAR=
Command line, with the actual value set:
$ MY_ENV_VAR=something pytest -c pytest.ini -s tests/**
I don't know why does it work like this. I just found out that it works as a result of mere trial and error, because the other answers didn't help me.
Although the other answer works I think this one is more "hands-off" and automated and it simulates normal operation more. So I use python-dotenv
to load all variables form a file with load_dotenv(my_filepath)
:
import os
import pytest
from dotenv import load_dotenv
from core import ConfigService
def test_config_service():
"""This test ensures that the config service can read the environment
variables which define the location of the config.json files"""
load_dotenv("env/common.env")
config_service = ConfigService()
config_service.load()
assert config_service.config_folder_path is not None
assert config_service.config_folder_name is not None
I think it is better if you want to test your whole logic of:
.env
file in a specific location andIf you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With