How to use pytest_addoption
By Pooja Deshpande, Community Contributor - January 2, 2025
In Python, command-line arguments can be used to add or modify a program’s runtime behavior. Passing the command-line arguments at runtime gives users the flexibility to monitor their program’s runtime behavior and desired outputs. One can do this by using the argparse/ standard input library in Python.
Now the question arises of how to extend this functionality to pytest?
pytest is a powerful, flexible, and widely used testing framework for Python. It is designed to make testing simple and efficient, providing developers with tools to write, organize, and execute tests for their Python code.
- What is Pytest Addoption?
- Syntax for pytest addoption
- Why should you use Pytest Addoption?
- What are the Similarities between Argparse and Pytest Adoption?
- When to use Argparse?
- When to use Addoption?
What is Pytest Addoption?
The pytest adoption feature extends the flexibility of command-line arguments in pytest by dynamically passing them to unit tests. This feature allows you to define custom command line arguments for tests.
For example, a login page requires multiple logins with different usernames and passwords to test functionalities for different user levels. In this case, one can pass the usernames and passwords as command-line arguments using pytest adoption.
This is a simple example, but this feature can be used to handle many complex applications that operate in multiple modes and require user input. These are referred to as CLI commands or flags.
Also Read: Pytest vs Unittest: A Comparison
Syntax for pytest addoption
Here is the code snippet for pytest addoption –
def pytest_addoption(parser): parser.addoption(“--all”, action=”store_true”,default = “default value” help=”run all combinations”)
Here is an explanation of what each parameter means –
- action – indicates what action needs to be taken as a given value. This parameter takes any of the below values.
Parameter | Description |
---|---|
store | (Default) Stores the options argument as string |
store_true | (Boolean option) Sets the options value to True. |
store _false | (Boolean option) Sets the options value to True. |
store_const | Stores a constant value |
count | Counts the number of times the option is specified in command line |
append | Appends argument to list |
append_const | Appends constant values to a list |
- default – Default value that will be used if no value is provided.
- help – Helpful description of what the action does.
Why should you use Pytest Addoption?
Pytest addoption is a powerful tool that helps to tailor your test behavior dynamically.
Here are a few advantages of using Pytest Addoption –
1. Flexibility in Test Configuration: Pytest’s adoption can help define custom command-line options that can dynamically adjust to the behaviour of your test suite.
For example –
- Running tests across different test environments (e.g.Staging, Prod etc)
- Passing credentials or API keys for Integration tests
# conftest.py def pytest_addoption(parser): parser.addoption("--env", action="store", default="dev", help="Environment to run tests against") pytest --env=staging
2. Dynamically Control Test Execution: Using custom options in Addoption, one can –
- Enable or disable specific tests
- Pass runtime parameter that controls test logic (e.g.Timeouts, Feature Flags)
def pytest_addoption(parser): parser.addoption("--feature-flag", action="store_true", help="Enable feature flag") def test_example(request): if request.config.getoption("--feature-flag"): assert True # Feature flag enabled logic else: assert False # Feature flag disabled logic
3. Reusability Across Tests: The options that are added through pytest addoption are globally available making them reusable across all tests in the test suite. This simplifies the code base and avoids duplication of code.
def pytest_addoption(parser): parser.addoption("--db-uri", action="store", help="Database connection string") @pytest.fixture def db_uri(request): return request.config.getoption("--db-uri") def test_database_connection(db_uri): assert db_uri == "postgres://user:password@localhost/db" #bash pytest --db-uri="postgres://user:password@localhost/db"
4. Seamless Integration with CI/CD: Command-line options can be defined that work well with CI/CD pipelines.
- Pass test environment configurations dynamically
- Toggle features or behaviours based on deployment stages.
pytest --env=ci --timeout=10
5. Improved Test Suite Scalability: Addoption helps to manage complexity by centralising configuration logic.This way it helps to reduce hardcoding in test scripts by passing values at runtime and also use the same scripts for different setups without modification.
6: Enhanced Debugging and Logging: With Addoption one can control debugging levels or logging verbosity directly from the command line:
def pytest_addoption(parser): parser.addoption("--debug", action="store_true", help="Enable debugging output") def test_debugging(request): if request.config.getoption("--debug"): print("Debugging mode enabled")
Also Read: How to Generate Pytest Code Coverage Report
What are the Similarities between Argparse and Pytest Adoption?
Argparse and Pytest Addoption aim to handle command-line arguments passed to Python scripts or commands at runtime. Both of them accept user inputs at runtime. They let you define options and retrieve their values at runtime.
With Argparse :
import argparse parser = argparse.ArgumentParser() parser.add_argument("--option", help="An example argument") args = parser.parse_args() print(args.option)
With Addoption :
# conftest.py def pytest_addoption(parser): parser.addoption("--option", help="An example argument") # test_example.py def test_example(request): option_value = request.config.getoption("--option") print(option_value)
Both allow you to define custom options with similar configurations:
- Option names (e.g., –flag, –env)
- Default values
- Help descriptions
- Action types (e.g., store a value, store a boolean flag)
With Argparse :
parser.add_argument("--debug", action="store_true", help="Enable debugging mode")
With Addoption :
def pytest_addoption(parser): parser.addoption("--debug", action="store_true", help="Enable debugging mode")
Both support default values for options if no value is provided at runtime.
With Argparse :
parser.add_argument("--env", default="development", help="Environment name")
With Addoption :
def pytest_addoption(parser): parser.addoption("--env", default="development", help="Environment name")
Now, how do you decide which one to use when both offer the same features? Here is the answer.
Also Read: Understanding Unit Testing in Python
When to use Argparse?
Argparse is the right choice when you are working with a general-purpose Python script that accepts command-line arguments. It can be used for standalone scripts, command-line tools, or when your script’s primary purpose is not related to running tests and there is no dependency on a testing framework.
When to use Addoption?
pytest addoption is the right choice when you need to customize the behavior of a pytest test suite by adding command-line options.
Prerequisites for using pytest_addoption
To effectively use pytest_addoption, you need a basic understanding of the pytest framework and some specific setup steps.
Here’s a list of prerequisites for using pytest_addoption:
Step 1. Install Python: Python (Version: 3.11+)
Step 2. Install pytest: pip install pytest
Verify after Installation
pytest –version
Step 3. Creating a conftest.py File: pytest_addoption hooks need to be placed in a conftest.py file, which acts as a configuration file for pytest. This file must be:
- In the root directory of your test suite or a subdirectory containing tests.
- Named conftest.py (it’s automatically recognized by pytest).
Example of root directory –
project/
│
├── tests/
│ ├── conftest.py
│ ├── test_example.py
Step 4. Familiarity with Pytest Hooks
Hooks in Pytest: pytest_addoption is a hook function in pytest.
One should understand what hooks are (Functions that allow you to customize or extend pytest) and how to define and use hooks in conftest.py.
Step 5. Basic Syntax of pytest_addoption
One should know how to:
- Use the parser object to add options.
- Define attributes like action, default, help, and type for options.
- Access the added options using request.config.getoption.
def pytest_addoption(parser): parser.addoption( "--env", action="store", default="dev", help="Specify the environment to run tests" )
How to use Pytest Addoption?
Using pytest addoption involves defining and accessing custom command-line options in your tests. This allows you to dynamically modify test behaviour or pass additional parameters to the test suite.
Below is a step-by-step guide:
1. Define a conftest.py file: The pytest adoption hook must be defined in the conftest.py file which serves as a configuration file for pytest.
project/
│
├── tests/
│ ├── conftest.py
│ ├── test_example.py
2. Implement pytest_addoption in conftest.py: The pytest_addoption hook defines custom command-line options. Create command line options like below-
# conftest.py def pytest_addoption(parser): parser.addoption( "--env", # The custom option action="store", # Stores the value provided default="dev", # Default value if not provided help="Specify the environment: dev, staging, or prod" # Help description )
3. Access the Custom Option in Tests using the request fixture: You can access the value of a custom option using request.config.getoption. Use the custom option in the test :
Example – use the “–env “option created in above step
def test_environment(request): env = request.config.getoption(“--env”) assert env in [“dev”, “staging”, “prod”], f”Invalid environment: {env}” print(f”Running tests in the {env} environment.”)
4. Run the Tests with the Custom Option: Use the custom command-line option when running pytest :
pytest --env=staging pytest --env=prod pytest # Uses the default value (`dev` in this case)
Example Use Case: Toggle a Feature Flag
You can define a boolean option (e.g., –feature-flag) to toggle features.
# conftest.py def pytest_addoption(parser): parser.addoption("--feature-flag", action="store_true", help="Enable the feature flag") # test_example.py def test_feature_flag(request): feature_flag = request.config.getoption("--feature-flag") if feature_flag: print("Feature flag is enabled!") assert True else: print("Feature flag is disabled!") assert False
Run :
pytest –feature-flag
pytest # Feature flag remains disabled
Common issues when using pytest_addoption
Using pytest_addoption can sometimes lead to issues, especially for those new to pytest or working with complex test setups.
Below are common issues you might encounter along with their solutions:
1. pytest_addoption is Not Recognized: Pytest does not recognize the pytest_addoption function, so your custom options are ignored.
This might be caused due to :
- pytest_addoption function is not placed in correct file(conftest.py)
- The conftest.py file is not in a directory that pytest scans.
Solution:
- Ensure pytest_addoption is defined in a conftest.py file.
- Place the conftest.py file in your test suite’s root directory or the directory where your tests reside.
2. Option Value Not Set Correctly: This occurs when the value of a custom option is not what you expect, even though the command-line argument was provided.
This might be caused due to :
- You passed an invalid value from the command line.
- The action, type, or default for the option is misconfigured.
Solution:
- Ensure the value passed on the command line matches the expected type.
- Verify the action, type, and default values in the pytest_addoption definition.
3. Tests Fail When Option is Not Passed: A test fails because the custom option is required but wasn’t provided on the command line. This might be caused by the option not having a default value and the test logic not handling a missing value.
Solution :
- Provide a sensible default value in pytest_addoption.
- Alternatively, use required=True in the option definition.
4. Errors When Using Fixtures with Options: Custom options in fixtures are not available or cause runtime errors.
This might be caused due to :
- The option is accessed before pytest parses it.
- The fixture is not defined properly.
Solution: Access options within the fixture using request.
5. CI/CD Integration Issues: This issue occurs when custom options are not recognized when running tests in a CI/CD pipeline. It might be caused by custom options not being passed correctly in the CI configuration.
Solution :
- Ensure you pass the options correctly in your CI job configuration.
- Example in a YAML-based CI pipeline:
steps:
run: pytest --env=staging
Best Practices for Using pytest_addoption with BrowserStack
To use pytest_addoption effectively, you must follow best practices to ensure that your custom options are robust, maintainable, and easy to use.
Integrate pytest with BrowserStack: One can also Integrate pytest with BrowserStack as using BrowserStack with pytest offers several benefits that enhance testing efficiency, coverage, and flexibility. BrowserStack offers seamless integration with pytest.
Learn More: Integrating Browserstack with pytest
BrowserStack also eases debugging and reporting by providing network logs, console logs, and screenshots for debugging failed tests.
Prerequisites
1. Sign up at BrowserStack.
2. Ensure pytest and selenium are installed:
pip install pytest selenium pip install browserstack-sdk
3. Install the BrowserStack Python SDK: Run the following command
pip install browserstack-sdk
4. Configure BrowserStack SDK
The BrowserStack SDK uses a configuration file to define test capabilities, such as browser, OS, and settings.
5. Create the Configuration File
- Create a file named browserstack.json in the root directory of your project.
Example –
{ "auth": { "username": "your_browserstack_username", "access_key": "your_browserstack_access_key" }, "browsers": [ { "browser": "chrome", "os": "Windows", "os_version": "10", "browser_version": "latest" }, { "browser": "firefox", "os": "OS X", "os_version": "Monterey", "browser_version": "latest" } ], "run_settings": { "cypress_config_file": false, "project_name": "Pytest Integration", "build_name": "Build 1", "exclude": [], "parallels": 5 } }
- Replace your_browserstack_username and your_browserstack_access_key with your BrowserStack credentials, available on the Account Settings page.
- Set Up a conftest.py: Configure a pytest fixture to initialize the BrowserStack WebDriver based on the SDK settings.
import pytest from selenium import webdriver from browserstack.local import Local import json import os @pytest.fixture(scope="session") def browserstack_local(): # Start BrowserStack Local for local testing if required local = Local() local_args = {"key": os.getenv("BROWSERSTACK_ACCESS_KEY")} local.start(**local_args) yield local.stop() @pytest.fixture def browser(request, browserstack_local): # Load capabilities from browserstack.json with open("browserstack.json") as f: config = json.load(f) capabilities = config["browsers"][0] # Example: Use the first browser capabilities["build"] = config["run_settings"]["build_name"] capabilities["name"] = request.node.name # Initialize WebDriver driver = webdriver.Remote( command_executor=f"https://{config['auth']['username']}:{config['auth']['access_key']}@hub-cloud.browserstack.com/wd/hub", desired_capabilities=capabilities ) yield driver driver.quit()
- Write Test Cases
def test_google_search(browser): browser.get("https://www.google.com") assert "Google" in browser.title
- Run the Tests: Execute the tests using pytest. The BrowserStack SDK will automatically pick up configurations from browserstack.json
Command : pytest
- Organise options in conftest.py: If you have many options to be defined, then organise them logically and define their purpose clearly in the file
- Provide Default Values: Always provide default values so that the tests run smoothly even when the option is not provided.
- Select the appropriate action type for the option:
- store: For options that take values.
- store_true/store_false: For boolean flags.
- append: For options that can accept multiple values.
- Document Custom Options: Use the help argument to describe the purpose of each option. Include usage examples in your project’s documentation or README.
- Ensure Compatibility with CI/CD Pipelines: Design custom options with CI/CD in mind:
- Use default values for local runs.
- Pass explicit options in the CI pipeline configuration.
Conclusion
The pytest_addoption feature is a powerful tool in the pytest ecosystem that allows developers to customize their test runs by adding command-line options. These options provide flexibility to control test behavior dynamically, integrate with external tools, and streamline testing workflows.
Key takeaways for pytest_addoption:
- Enhanced Flexibility: Custom options enable tailoring test runs to specific environments or configurations, making tests adaptable and reusable.
- Seamless Integration: External tools, APIs, or services can be easily incorporated into the testing process by using pytest_addoption.
- Dynamic Configuration: You can dynamically pass parameters like environment variables, feature flags, or timeouts to your test suite, reducing the need for hard coding.
- Improved Collaboration: Documented custom options improve collaboration among team members, especially in large or multi-environment projects.
pytest_addoption transforms test execution by offering a user-friendly and highly configurable approach. Leveraging this feature ensures your test suite is more flexible and scalable, easier to maintain, and more adaptable to varying project needs.