├── .flake8 ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── release.yml │ └── tests.yml ├── .gitignore ├── .pre-commit-config.yaml ├── CHANGELOG.md ├── CONTRIBUTING.rst ├── LICENSE ├── MANIFEST.in ├── README.md ├── examples ├── attributes │ ├── test_one_attribute.py │ ├── test_runtime_attribute.py │ └── test_two_attributes_with_same_key.py ├── bdd │ ├── features │ │ ├── arguments_four_steps.feature │ │ ├── arguments_four_steps_description.feature │ │ ├── arguments_four_steps_docstring.feature │ │ ├── arguments_three_steps.feature │ │ ├── arguments_two_scenarios.feature │ │ ├── background_scenario.feature │ │ ├── background_two_steps.feature │ │ ├── belly.feature │ │ ├── custom_test_case_id.feature │ │ ├── data_table_parameter.feature │ │ ├── doc_string_parameters.feature │ │ ├── dynamic_scenario_outline_names.feature │ │ ├── examples_tags.feature │ │ ├── failed_scenario.feature │ │ ├── long_step_scenario.feature │ │ ├── rule_description.feature │ │ ├── rule_keyword.feature │ │ ├── scenario_outline_background.feature │ │ ├── scenario_outline_description.feature │ │ ├── scenario_outline_fail.feature │ │ ├── scenario_outline_parameters.feature │ │ └── scenario_outline_test_case_id.feature │ └── step_defs │ │ ├── __init__.py │ │ ├── custom_test_case_id_steps.py │ │ ├── data_table_parameter_steps.py │ │ ├── doc_string_parameters_steps.py │ │ ├── example_tags_steps.py │ │ ├── long_step_scenario_steps.py │ │ ├── scenario_outline_background_steps.py │ │ ├── scenario_outline_description_steps.py │ │ ├── scenario_outline_fail_steps.py │ │ ├── scenario_outline_name_steps.py │ │ ├── scenario_outline_parameters_steps.py │ │ ├── scenario_outline_test_case_id_steps.py │ │ ├── test_arguments.py │ │ ├── test_arguments_description.py │ │ ├── test_arguments_two_features.py │ │ ├── test_arguments_two_scenarios.py │ │ ├── test_background.py │ │ ├── test_background_two_steps.py │ │ ├── test_belly.py │ │ ├── test_failed_step.py │ │ ├── test_rule_description_steps.py │ │ └── test_rule_steps.py ├── custom_name │ ├── test_custom_name_args.py │ ├── test_custom_name_empty.py │ └── test_custom_name_kwargs.py ├── empty │ └── README.txt ├── fixtures │ ├── class_fixture_return │ │ ├── conftest.py │ │ └── test_fixture_class_setup.py │ ├── module_fixture_return │ │ ├── conftest.py │ │ └── test_fixture_module_setup.py │ ├── package_fixture_return │ │ ├── __init__.py │ │ ├── conftest.py │ │ ├── test_fixture_package_setup_first.py │ │ └── test_fixture_package_setup_second.py │ ├── session_fixture_return │ │ ├── conftest.py │ │ ├── test_fixture_session_setup_first.py │ │ └── test_fixture_session_setup_second.py │ ├── test_failure_fixture_teardown │ │ ├── conftest.py │ │ └── test_failure_fixture_teardown.py │ ├── test_fixture_exit │ │ └── test_fixture_exit.py │ ├── test_fixture_return_none │ │ ├── conftest.py │ │ └── test_fixture_return_none.py │ ├── test_fixture_setup │ │ ├── conftest.py │ │ └── test_fixture_setup.py │ ├── test_fixture_setup_failure │ │ ├── conftest.py │ │ └── test_fixture_setup_failure.py │ ├── test_fixture_skipped │ │ └── test_fixture_skipped.py │ ├── test_fixture_teardown │ │ ├── conftest.py │ │ └── test_fixture_teardown.py │ ├── test_fixture_teardown_failure │ │ ├── conftest.py │ │ └── test_fixture_teardown_failure.py │ └── test_fixture_yield_none │ │ ├── conftest.py │ │ └── test_fixture_yield_none.py ├── hierarchy │ ├── another_inner │ │ └── test_another_inner_simple.py │ ├── inner │ │ └── test_inner_simple.py │ ├── test_in_class.py │ └── test_in_class_in_class.py ├── params │ ├── test_binary_symbol_in_parameters.py │ ├── test_different_parameter_types.py │ └── test_in_class_parameterized.py ├── skip │ ├── test_simple_skip.py │ └── test_skip_issue.py ├── test_case_id │ ├── test_case_id_decorator.py │ ├── test_case_id_decorator_no_id.py │ ├── test_case_id_decorator_no_id_params_false.py │ ├── test_case_id_decorator_no_id_params_true.py │ ├── test_case_id_decorator_no_id_partial_params.py │ ├── test_case_id_decorator_no_id_partial_params_true.py │ ├── test_case_id_decorator_params_false.py │ ├── test_case_id_decorator_params_no.py │ ├── test_case_id_decorator_params_partially.py │ └── test_case_id_decorator_params_true.py ├── test_issue_id.py ├── test_issue_id_pass.py ├── test_max_item_name.py ├── test_rp_logging.py ├── test_simple.py ├── test_simple_fail.py └── threads │ └── test_thread_logging.py ├── pyproject.toml ├── pytest_reportportal ├── __init__.py ├── config.py ├── errors.py ├── plugin.py ├── rp_logging.py └── service.py ├── requirements-dev-bdd.txt ├── requirements-dev.txt ├── requirements.txt ├── setup.cfg ├── setup.py ├── tests ├── __init__.py ├── helpers │ ├── __init__.py │ └── utils.py ├── integration │ ├── __init__.py │ ├── test_attributes.py │ ├── test_bdd.py │ ├── test_case_id_report.py │ ├── test_code_reference.py │ ├── test_config_handling.py │ ├── test_connection_close.py │ ├── test_custom_name.py │ ├── test_debug_mode.py │ ├── test_empty_run.py │ ├── test_fixtures.py │ ├── test_issue_report.py │ ├── test_max_name_length.py │ ├── test_parameters_report.py │ ├── test_pass_failed_skipped.py │ ├── test_pytest_parallel.py │ ├── test_suite_hierarchy.py │ └── test_threads_logs.py └── unit │ ├── __init__.py │ ├── conftest.py │ ├── test_config.py │ ├── test_plugin.py │ └── test_service.py └── tox.ini /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 119 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **Steps to Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. ... 16 | 2. ... 17 | 18 | **Expected behavior** 19 | A clear and concise description of what you expected to happen. 20 | 21 | **Actual behavior** 22 | What actually happened. 23 | 24 | **Package versions** 25 | Include version info of the following packages: reportportal-client, pytest-reportportal 26 | 27 | **Additional context** 28 | Add any other context about the problem here. 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 EPAM Systems 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License. 13 | 14 | name: Release Pytest agent 15 | 16 | on: 17 | push: 18 | branches: [ 'master' ] 19 | paths-ignore: 20 | - '.github/**' 21 | - CHANGELOG.md 22 | - README.md 23 | - CONTRIBUTING.rst 24 | 25 | env: 26 | VERSION_FILE: setup.py 27 | VERSION_EXTRACT_PATTERN: >- 28 | __version__\s*=\s*"([^"]+) 29 | VERSION_REPLACE_PATTERN: >- 30 | __version__ = "\1" 31 | TMP_SUFFIX: _updated 32 | CHANGE_LOG_FILE: CHANGELOG.md 33 | 34 | jobs: 35 | deploy: 36 | runs-on: ubuntu-latest 37 | steps: 38 | - name: Checkout repository 39 | uses: actions/checkout@v4 40 | 41 | - name: Generate versions 42 | uses: HardNorth/github-version-generate@v1 43 | with: 44 | version-source: file 45 | version-file: ${{ env.VERSION_FILE }} 46 | version-file-extraction-pattern: ${{ env.VERSION_EXTRACT_PATTERN }} 47 | 48 | - name: Set up Python 49 | uses: actions/setup-python@v5 50 | with: 51 | python-version: '3.10' 52 | 53 | - name: Install dependencies 54 | run: python -m pip install --upgrade pip setuptools wheel 55 | 56 | - name: Build package 57 | run: python setup.py sdist bdist_wheel 58 | 59 | - name: Publish package 60 | uses: pypa/gh-action-pypi-publish@release/v1 61 | with: 62 | user: ${{ secrets.PYPI_USERNAME }} 63 | password: ${{ secrets.PYPI_PASSWORD }} 64 | 65 | - name: Setup git credentials 66 | uses: oleksiyrudenko/gha-git-credentials@v2-latest 67 | with: 68 | name: 'reportportal.io' 69 | email: 'support@reportportal.io' 70 | token: ${{ secrets.GITHUB_TOKEN }} 71 | 72 | - name: Tagging new version 73 | id: newVersionTag 74 | run: | 75 | git tag -a ${{ env.RELEASE_VERSION }} -m "Release ${{ env.RELEASE_VERSION }}" 76 | git push --tags 77 | 78 | - name: Checkout develop branch 79 | uses: actions/checkout@v4 80 | with: 81 | ref: 'develop' 82 | fetch-depth: 0 83 | 84 | - name: Merge release branch into develop 85 | id: mergeIntoDevelop 86 | run: | 87 | git merge -m 'Merge master branch into develop after a release' origin/master 88 | git status | (! grep -Fq 'both modified:') || git status | grep -F 'both modified:' \ 89 | | { echo -e 'Unable to merge master into develop, merge conflicts:'; (! grep -Eo '[^ ]+$') } 90 | 91 | - name: Update CHANGELOG.md 92 | id: changelogUpdate 93 | run: | 94 | sed '/\[Unreleased\]/q' ${{ env.CHANGE_LOG_FILE }} >> ${{ env.CHANGE_LOG_FILE }}${{ env.TMP_SUFFIX }} 95 | sed -E '1,/#?#\s*\[Unreleased\]/d' ${{ env.CHANGE_LOG_FILE }} | sed -E '/#?#\s*\[/q' | \ 96 | { echo -e '\n## [${{ env.RELEASE_VERSION }}]'; sed '$d'; } >> ${{ env.CHANGE_LOG_FILE }}${{ env.TMP_SUFFIX }} 97 | grep -E '#?#\s*\[[0-9]' ${{ env.CHANGE_LOG_FILE }} | head -n1 >> ${{ env.CHANGE_LOG_FILE }}${{ env.TMP_SUFFIX }} 98 | sed -E '1,/#?#\s*\[[0-9]/d' ${{ env.CHANGE_LOG_FILE }} >> ${{ env.CHANGE_LOG_FILE }}${{ env.TMP_SUFFIX }} 99 | rm ${{ env.CHANGE_LOG_FILE }} 100 | mv ${{ env.CHANGE_LOG_FILE }}${{ env.TMP_SUFFIX }} ${{ env.CHANGE_LOG_FILE }} 101 | git add ${{ env.CHANGE_LOG_FILE }} 102 | git commit -m "Changelog update" 103 | 104 | - name: Read changelog Entry 105 | id: readChangelogEntry 106 | uses: mindsers/changelog-reader-action@v2 107 | with: 108 | version: ${{ env.RELEASE_VERSION }} 109 | path: ./${{ env.CHANGE_LOG_FILE }} 110 | 111 | - name: Create Release 112 | id: createRelease 113 | uses: ncipollo/release-action@v1 114 | with: 115 | tag: ${{ env.RELEASE_VERSION }} 116 | name: Release ${{ env.RELEASE_VERSION }} 117 | body: ${{ steps.readChangelogEntry.outputs.changes }} 118 | 119 | - name: Update version file 120 | id: versionFileUpdate 121 | run: | 122 | export CURRENT_VERSION_VALUE=`echo '${{ env.CURRENT_VERSION }}' | sed -E 's/(.*)/${{ env.VERSION_REPLACE_PATTERN }}/'` 123 | export NEXT_VERSION_VALUE=`echo '${{ env.NEXT_VERSION }}' | sed -E 's/(.*)/${{ env.VERSION_REPLACE_PATTERN }}/'` 124 | sed "s/${CURRENT_VERSION_VALUE}/${NEXT_VERSION_VALUE}/g" ${{ env.VERSION_FILE }} > ${{ env.VERSION_FILE }}${{ env.TMP_SUFFIX }} 125 | rm ${{ env.VERSION_FILE }} 126 | mv ${{ env.VERSION_FILE }}${{ env.TMP_SUFFIX }} ${{ env.VERSION_FILE }} 127 | git add ${{ env.VERSION_FILE }} 128 | git commit -m 'Version update' 129 | git push 130 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2022 EPAM Systems 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License. 13 | 14 | name: Tests 15 | 16 | on: [ push, pull_request ] 17 | 18 | jobs: 19 | build: 20 | runs-on: ubuntu-latest 21 | strategy: 22 | matrix: 23 | python-version: [ '3.8', '3.9', '3.10', '3.11', '3.12', '3.13' ] 24 | steps: 25 | - name: Checkout repository 26 | uses: actions/checkout@v4 27 | 28 | - name: Set up Python ${{ matrix.python-version }} 29 | uses: actions/setup-python@v5 30 | with: 31 | python-version: ${{ matrix.python-version }} 32 | 33 | - name: Install dependencies 34 | run: | 35 | python -m pip install --upgrade pip 36 | pip install tox tox-gh-actions 37 | 38 | - name: Test with tox 39 | run: tox 40 | 41 | - name: Upload coverage to Codecov 42 | if: matrix.python-version == 3.10 && success() 43 | uses: codecov/codecov-action@v4 44 | with: 45 | token: ${{ secrets.CODECOV_TOKEN }} 46 | files: coverage.xml 47 | flags: unittests 48 | name: codecov-client-reportportal 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | .idea/ 54 | 55 | # Translations 56 | *.mo 57 | *.pot 58 | 59 | # Django stuff: 60 | *.log 61 | local_settings.py 62 | db.sqlite3 63 | db.sqlite3-journal 64 | 65 | # Flask stuff: 66 | instance/ 67 | .webassets-cache 68 | 69 | # Scrapy stuff: 70 | .scrapy 71 | 72 | # Sphinx documentation 73 | docs/_build/ 74 | 75 | # PyBuilder 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | .python-version 87 | 88 | # pipenv 89 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 90 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 91 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 92 | # install all needed dependencies. 93 | #Pipfile.lock 94 | 95 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 96 | __pypackages__/ 97 | 98 | # Celery stuff 99 | celerybeat-schedule 100 | celerybeat.pid 101 | 102 | # SageMath parsed files 103 | *.sage.py 104 | 105 | # Environments 106 | .env 107 | .venv 108 | env/ 109 | venv/ 110 | ENV/ 111 | env.bak/ 112 | venv.bak/ 113 | 114 | # Spyder project settings 115 | .spyderproject 116 | .spyproject 117 | 118 | # Rope project settings 119 | .ropeproject 120 | 121 | # mkdocs documentation 122 | /site 123 | 124 | # mypy 125 | .mypy_cache/ 126 | .dmypy.json 127 | dmypy.json 128 | 129 | # Pyre type checker 130 | .pyre/ 131 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # See https://pre-commit.com for more information 2 | # See https://pre-commit.com/hooks.html for more hooks 3 | repos: 4 | - repo: https://github.com/pre-commit/pre-commit-hooks 5 | rev: v5.0.0 6 | hooks: 7 | - id: trailing-whitespace 8 | - id: end-of-file-fixer 9 | - id: check-yaml 10 | - id: check-added-large-files 11 | - repo: https://github.com/PyCQA/pydocstyle 12 | rev: 6.3.0 13 | hooks: 14 | - id: pydocstyle 15 | exclude: | 16 | (?x)^( 17 | tests/.* | 18 | examples/.* 19 | ) 20 | - repo: https://github.com/psf/black 21 | rev: 24.10.0 22 | hooks: 23 | - id: black 24 | args: [ '--check', 'pytest_reportportal', 'tests' ] 25 | - repo: https://github.com/pycqa/isort 26 | rev: 6.0.0 27 | hooks: 28 | - id: isort 29 | - repo: https://github.com/pycqa/flake8 30 | rev: 7.1.1 31 | hooks: 32 | - id: flake8 33 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [Unreleased] 4 | ### Added 5 | - Too long BDD Step name truncation on reporting, by @HardNorth 6 | 7 | ## [5.5.0] 8 | ### Added 9 | - Issue [#357](https://github.com/reportportal/agent-python-pytest/issues/357) `pytest-bdd` support, by @HardNorth 10 | ### Fixed 11 | - Issue [#389](https://github.com/reportportal/agent-python-pytest/issues/389) `rp_tests_attributes` configuration parameter handling, by @HardNorth 12 | - Issue [#390](https://github.com/reportportal/agent-python-pytest/issues/390) INTERNALERROR due to pytest.exit within fixture, by @HardNorth 13 | ### Removed 14 | - `Python 3.7` support, by @HardNorth 15 | 16 | ## [5.4.7] 17 | ### Added 18 | - Issue [#382](https://github.com/reportportal/agent-python-pytest/issues/382): Escaping of binary symbol '\0' in parameters, by @HardNorth 19 | ### Changed 20 | - Client version updated on [5.6.0](https://github.com/reportportal/client-Python/releases/tag/5.6.0), by @HardNorth 21 | 22 | ## [5.4.6] 23 | ### Added 24 | - Support for `Python 3.13`, by @HardNorth 25 | - Support for `name` Pytest marker, by @HardNorth 26 | - `rp_hierarchy_test_file` configuration parameter, which controls display of test file name in the hierarchy, by @ramir-dn, @HardNorth 27 | ### Fixed 28 | - Agent crash if Client could not be initialized, by @HardNorth 29 | ### Changed 30 | - Client version updated on [5.5.10](https://github.com/reportportal/client-Python/releases/tag/5.5.10), by @HardNorth 31 | 32 | ## [5.4.5] 33 | ### Fixed 34 | - Issue [#379](https://github.com/reportportal/agent-python-pytest/issues/379): Fix TypeError when using pytest.skip() in fixtures, by @HardNorth 35 | 36 | ## [5.4.4] 37 | ### Fixed 38 | - Issue [#375](https://github.com/reportportal/agent-python-pytest/issues/375): Fix max Item name length, by @HardNorth 39 | 40 | ## [5.4.3] 41 | ### Added 42 | - Issue [#332](https://github.com/reportportal/agent-python-pytest/issues/332): Support for fixture reporting, by @HardNorth 43 | 44 | ## [5.4.2] 45 | ### Fixed 46 | - Issue [#368](https://github.com/reportportal/agent-python-pytest/issues/368): Distutils in the agent, by @HardNorth 47 | - Pytest Tavern plugin support, by @virdok 48 | ### Added 49 | - Python 12 support, by @HardNorth 50 | 51 | ## [5.4.1] 52 | ### Fixed 53 | - Issue [#362](https://github.com/reportportal/agent-python-pytest/issues/362): Debug mode passing, by @HardNorth 54 | 55 | ## [5.4.0] 56 | ### Added 57 | - Pytest version >= 8 support, by @HardNorth 58 | ### Removed 59 | - `Package` and `Dir` item types processing on test collection. This is done to preserve backward compatibility and improve name consistency, by @HardNorth 60 | ### Changed 61 | - `rp_issue_system_url` renamed to `rp_bts_issue_url` to be consistent with other agents, by @HardNorth 62 | 63 | ## [5.3.2] 64 | ### Changed 65 | - Set upper pytest version limit to not include `8.0.0`, by @HardNorth 66 | 67 | ## [5.3.1] 68 | ### Changed 69 | - Client version updated on [5.5.4](https://github.com/reportportal/client-Python/releases/tag/5.5.4), by @HardNorth 70 | - `rp_launch_id` property handling moved completely on Client side, by @HardNorth 71 | 72 | ## [5.3.0] 73 | ### Added 74 | - `rp_client_type` configuration variable, by @HardNorth 75 | - `rp_connect_timeout` and `rp_read_timeout` configuration variables, by @HardNorth 76 | ### Changed 77 | - Client version updated on [5.5.2](https://github.com/reportportal/client-Python/releases/tag/5.5.2), by @HardNorth 78 | 79 | ## [5.2.2] 80 | ### Changed 81 | - Client version updated on [5.4.1](https://github.com/reportportal/client-Python/releases/tag/5.4.1), by @HardNorth 82 | 83 | ## [5.2.1] 84 | ### Fixed 85 | - Log line reference for Python 3.11, by @HardNorth 86 | ### Changed 87 | - Client version updated on [5.4.0](https://github.com/reportportal/client-Python/releases/tag/5.4.0), by @HardNorth 88 | 89 | ## [5.2.0] 90 | ### Added 91 | - `rp_launch_uuid_print` and `rp_launch_uuid_print_output` configuration parameters, by @HardNorth 92 | ### Removed 93 | - Python 2.7, 3.6 support, by @HardNorth 94 | 95 | ## [5.1.9] 96 | ### Added 97 | - `rp_api_retries` configuration parameter, by @HardNorth 98 | ### Changed 99 | - Client version updated on [5.3.5](https://github.com/reportportal/client-Python/releases/tag/5.3.5), by @HardNorth 100 | - `rp_uuid` configuration parameter was renamed to `rp_api_key` to maintain common convention, by @HardNorth 101 | 102 | ## [5.1.8] 103 | ### Fixed 104 | - `rp_thread_logging = False` config parameter handling, by @HardNorth 105 | - Recursive thread init issue in case of `rp_thread_logging = True`, by @HardNorth 106 | ### Changed 107 | - Client version updated on [5.3.2](https://github.com/reportportal/client-Python/releases/tag/5.3.2), by @HardNorth 108 | 109 | ## [5.1.7] 110 | ### Fixed 111 | - Plugin Exception in case of Launch creation timed out, by @HardNorth 112 | ### Changed 113 | - Client version updated on [5.3.1](https://github.com/reportportal/client-Python/releases/tag/5.3.1), by @HardNorth 114 | 115 | ## [5.1.6] 116 | ### Changed 117 | - Client version updated on [5.3.0](https://github.com/reportportal/client-Python/releases/tag/5.3.0), by @HardNorth 118 | 119 | ## [5.1.5] 120 | ### Added 121 | - Support of runtime issue adding, by @HardNorth 122 | 123 | ## [5.1.4] 124 | ### Added 125 | - Feature [#325](https://github.com/reportportal/agent-python-pytest/issues/325) Support of runtime attribute adding, by @yakovbabich, @HardNorth 126 | - `rp_launch_timeout` parameter to limit test execution in case of process hanging, by @HardNorth 127 | 128 | ## [5.1.3] 129 | ### Added 130 | - Support for thread logs and `rp_thread_logging` flag, by @dagansandler 131 | 132 | ## [5.1.2] 133 | ### Added 134 | - `rp_log_batch_payload_size` parameter, by @HardNorth 135 | ### Changed 136 | - Feature [#311](https://github.com/reportportal/agent-python-pytest/issues/311): 137 | Adding log format config option, by @dagansandler 138 | 139 | ## [5.1.1] 140 | ### Fixed 141 | - Issue [#304](https://github.com/reportportal/agent-python-pytest/issues/304): 142 | SSL certificate flag handling issue, by @HardNorth 143 | 144 | ## [5.1.0] 145 | ### Changed 146 | - Agent complete rewrite, by @HardNorth 147 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Contribution 3 | ============ 4 | 5 | Contributions are highly welcomed and appreciated. 6 | 7 | .. contents:: 8 | :depth: 2 9 | :backlinks: none 10 | 11 | Feature requests 12 | ---------------- 13 | 14 | We'd also like to hear about your thoughts and suggestions. Feel free to 15 | `submit them as issues `_ and: 16 | 17 | * Explain in detail how they should work. 18 | * Keep the scope as narrow as possible. It will make it easier to implement. 19 | 20 | Bug reports 21 | ----------- 22 | 23 | Report bugs for the agent in the `issue tracker `_. 24 | 25 | If you are reporting a new bug, please include: 26 | 27 | * Your operating system name and version. 28 | * Python interpreter version, installed libraries, reportportal-client, and agent-python-pytest 29 | version. 30 | * Detailed steps to reproduce the bug. 31 | 32 | Bug fixes 33 | --------- 34 | 35 | Look through the `GitHub issues for bugs `_. 36 | 37 | If you are gonna fix any of existing bugs, assign that bug to yourself and specify preliminary milestones. 38 | Talk to `contributors `_ in case you need a 39 | consultancy regarding implementation. 40 | 41 | Implement features 42 | ------------------ 43 | 44 | Look through the `GitHub issues for enhancements `_. 45 | 46 | Talk to `contributors `_ in case you need a 47 | consultancy regarding implementation. 48 | 49 | Preparing Pull Requests 50 | ----------------------- 51 | 52 | What is a "pull request"? It informs the project's core developers about the 53 | changes you want to review and merge. Pull requests are stored on 54 | `GitHub servers `_. 55 | Once you send a pull request, we can discuss its potential modifications and 56 | even add more commits to it later on. There's an excellent tutorial on how Pull 57 | Requests work in the 58 | `GitHub Help Center `_. 59 | 60 | Here is a simple overview below: 61 | 62 | #. Fork the 63 | `agent-python-pytest GitHub repository `_. 64 | 65 | #. Clone your fork locally using `git `_ and create a branch:: 66 | 67 | $ git clone git@github.com:YOUR_GITHUB_USERNAME/agent-python-pytest.git 68 | $ cd agent-python-pytest 69 | # now, create your own branch off the "master": 70 | 71 | $ git checkout -b your-bugfix-branch-name 72 | 73 | If you need some help with Git, follow this quick start 74 | guide: https://git.wiki.kernel.org/index.php/QuickStart 75 | 76 | #. Install `pre-commit `_ and its hook on the agent-python-pytest repo: 77 | 78 | **Note: pre-commit must be installed as admin, as it will not function otherwise**:: 79 | 80 | 81 | $ pip install --user pre-commit 82 | $ pre-commit install 83 | 84 | Afterwards ``pre-commit`` will run whenever you commit. 85 | 86 | https://pre-commit.com/ is a framework for managing and maintaining multi-language pre-commit hooks 87 | to ensure code-style and code formatting is consistent. 88 | 89 | #. Install tox 90 | 91 | Tox is used to run all the tests and will automatically setup virtualenvs 92 | to run the tests in. 93 | (will implicitly use http://www.virtualenv.org/en/latest/):: 94 | 95 | $ pip install tox 96 | 97 | #. Run all the tests 98 | 99 | You need to have Python 3.6 available in your system. Now 100 | running tests is as simple as issuing this command:: 101 | 102 | $ tox -e pep,py36 103 | 104 | This command will run tests via the "tox" tool against Python 3.6 105 | and also perform code style checks. 106 | 107 | #. You can now edit your local working copy and run the tests again as necessary. Please follow PEP-8 recommendations. 108 | 109 | You can pass different options to ``tox``. For example, to run tests on Python 3.6 and pass options to pytest 110 | (e.g. enter pdb on failure) to pytest you can do:: 111 | 112 | $ tox -e py36 -- --pdb 113 | 114 | Or to only run tests in a particular test module on Python 3.6:: 115 | 116 | $ tox -e py36 -- tests/test_service.py 117 | 118 | 119 | When committing, ``pre-commit`` will re-format the files if necessary. 120 | 121 | #. If instead of using ``tox`` you prefer to run the tests directly, then we suggest to create a virtual environment and use 122 | an editable install with the ``testing`` extra:: 123 | 124 | $ python3 -m venv .venv 125 | $ source .venv/bin/activate # Linux 126 | $ .venv/Scripts/activate.bat # Windows 127 | $ pip install -e ".[testing]" 128 | 129 | Afterwards, you can edit the files and run pytest normally:: 130 | 131 | $ pytest tests/test_service.py 132 | 133 | 134 | #. Commit and push once your tests pass and you are happy with your change(s):: 135 | 136 | $ git commit -m "" 137 | $ git push -u 138 | 139 | 140 | #. Finally, submit a pull request through the GitHub website using this data:: 141 | 142 | head-fork: YOUR_GITHUB_USERNAME/agent-python-pytest 143 | compare: your-branch-name 144 | 145 | base-fork: reportportal/agent-python-pytest 146 | base: master 147 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include MANIFEST.in 2 | include README.rst CONTRIBUTING.rst requirements.txt 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ReportPortal integration for pytest framework 2 | 3 | Pytest plugin for reporting test results of the Pytest to the ReportPortal. 4 | 5 | > **DISCLAIMER**: We use Google Analytics for sending anonymous usage information such as agent's and client's names, 6 | > and their versions after a successful launch start. This information might help us to improve both ReportPortal 7 | > backend and client sides. It is used by the ReportPortal team only and is not supposed for sharing with 3rd parties. 8 | 9 | [![PyPI](https://img.shields.io/pypi/v/pytest-reportportal.svg?maxAge=259200)](https://pypi.python.org/pypi/pytest-reportportal) 10 | [![Python versions](https://img.shields.io/pypi/pyversions/pytest-reportportal.svg)](https://pypi.org/project/pytest-reportportal) 11 | [![Tests](https://github.com/reportportal/agent-python-pytest/actions/workflows/tests.yml/badge.svg)](https://github.com/reportportal/agent-python-pytest/actions/workflows/tests.yml) 12 | [![codecov](https://codecov.io/gh/reportportal/agent-python-pytest/graph/badge.svg?token=x5ZHqZKJFV)](https://codecov.io/gh/reportportal/agent-python-pytest) 13 | [![Join Slack chat!](https://img.shields.io/badge/slack-join-brightgreen.svg)](https://slack.epmrpp.reportportal.io/) 14 | [![stackoverflow](https://img.shields.io/badge/reportportal-stackoverflow-orange.svg?style=flat)](http://stackoverflow.com/questions/tagged/reportportal) 15 | [![Build with Love](https://img.shields.io/badge/build%20with-❤%EF%B8%8F%E2%80%8D-lightgrey.svg)](http://reportportal.io?style=flat) 16 | 17 | ## Installation 18 | 19 | To install pytest plugin execute next command in a terminal: 20 | 21 | ```bash 22 | pip install pytest-reportportal 23 | ``` 24 | 25 | Look through the `CONTRIBUTING.rst` for contribution guidelines. 26 | 27 | ## Configuration 28 | 29 | Prepare the config file `pytest.ini` in root directory of tests or specify any one using pytest command line option: 30 | 31 | ```bash 32 | py.test -c config.cfg 33 | ``` 34 | 35 | The `pytest.ini` file should have next mandatory fields: 36 | 37 | - `rp_api_key` - value could be found in the User Profile section 38 | - `rp_project` - name of project in ReportPortal 39 | - `rp_endpoint` - address of ReportPortal Server 40 | 41 | Example of `pytest.ini`: 42 | 43 | ```text 44 | [pytest] 45 | rp_api_key = fb586627-32be-47dd-93c1-678873458a5f 46 | rp_endpoint = http://192.168.1.10:8080 47 | rp_project = user_personal 48 | rp_launch = AnyLaunchName 49 | rp_launch_attributes = 'PyTest' 'Smoke' 50 | rp_launch_description = 'Smoke test' 51 | rp_ignore_attributes = 'xfail' 'usefixture' 52 | ``` 53 | 54 | - The `rp_api_key` can also be set with the environment variable `RP_API_KEY`. This will override the value set for `rp_api_key` in pytest.ini 55 | 56 | There are also optional parameters: 57 | https://reportportal.io/docs/log-data-in-reportportal/test-framework-integration/Python/pytest/ 58 | 59 | ## Examples 60 | 61 | For logging of the test item flow to ReportPortal, please, use the python logging handler provided by plugin like 62 | below: 63 | 64 | in `conftest.py`: 65 | 66 | ```python 67 | import logging 68 | 69 | import pytest 70 | 71 | from reportportal_client import RPLogger 72 | 73 | 74 | @pytest.fixture(scope="session") 75 | def rp_logger(): 76 | logger = logging.getLogger(__name__) 77 | logger.setLevel(logging.DEBUG) 78 | logging.setLoggerClass(RPLogger) 79 | return logger 80 | ``` 81 | 82 | in tests: 83 | 84 | ```python 85 | # In this case only INFO messages will be sent to the ReportPortal. 86 | def test_one(rp_logger): 87 | rp_logger.info("Case1. Step1") 88 | x = "this" 89 | rp_logger.info("x is: %s", x) 90 | assert 'h' in x 91 | 92 | # Message with an attachment. 93 | import subprocess 94 | free_memory = subprocess.check_output("free -h".split()) 95 | rp_logger.info( 96 | "Case1. Memory consumption", 97 | attachment={ 98 | "name": "free_memory.txt", 99 | "data": free_memory, 100 | "mime": "application/octet-stream", 101 | }, 102 | ) 103 | 104 | # This debug message will not be sent to the ReportPortal. 105 | rp_logger.debug("Case1. Debug message") 106 | ``` 107 | 108 | ## Launching 109 | 110 | To run test with ReportPortal you must provide `--reportportal` flag: 111 | 112 | ```bash 113 | py.test ./tests --reportportal 114 | ``` 115 | 116 | Check the documentation to find more detailed information about how to integrate pytest with ReportPortal using the 117 | agent: 118 | https://reportportal.io/docs/log-data-in-reportportal/test-framework-integration/Python/pytest/ 119 | 120 | ## Copyright Notice 121 | 122 | Licensed under the [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0) license (see the LICENSE file). 123 | -------------------------------------------------------------------------------- /examples/attributes/test_one_attribute.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 https://reportportal.io . 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | import pytest 15 | 16 | 17 | @pytest.mark.scope("smoke") 18 | def test_custom_attributes_report(): 19 | """ 20 | This is a test with one custom marker which shall appear on 21 | ReportPortal on test's item 22 | """ 23 | assert True 24 | -------------------------------------------------------------------------------- /examples/attributes/test_runtime_attribute.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 https://reportportal.io . 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | import pytest 15 | 16 | 17 | @pytest.mark.scope("smoke") 18 | def test_custom_attributes_report(request): 19 | """ 20 | This is a test with one custom marker as a decorator and one custom marker 21 | added at runtime which shall both appear on ReportPortal on test's item 22 | """ 23 | request.node.add_marker(pytest.mark.runtime()) 24 | assert True 25 | -------------------------------------------------------------------------------- /examples/attributes/test_two_attributes_with_same_key.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 https://reportportal.io . 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | import pytest 15 | 16 | 17 | @pytest.mark.scope("smoke") 18 | @pytest.mark.scope("regression") 19 | def test_custom_attributes_report(): 20 | """ 21 | This is a test with multiple custom markers which shall appear on 22 | ReportPortal on test's item as different attributes 23 | """ 24 | assert True 25 | -------------------------------------------------------------------------------- /examples/bdd/features/arguments_four_steps.feature: -------------------------------------------------------------------------------- 1 | Feature: Four step arguments 2 | Scenario: Arguments for given, when, and, then 3 | Given there are 5 cucumbers 4 | 5 | When I eat 3 cucumbers 6 | And I eat 2 cucumbers 7 | 8 | Then I should have 0 cucumbers 9 | -------------------------------------------------------------------------------- /examples/bdd/features/arguments_four_steps_description.feature: -------------------------------------------------------------------------------- 1 | Feature: Four step arguments 2 | Description for the feature 3 | 4 | Scenario: Arguments for given, when, and, then 5 | Description for the scenario 6 | 7 | Given there are 5 cucumbers 8 | When I eat 3 cucumbers 9 | And I eat 2 cucumbers 10 | 11 | Then I should have 0 cucumbers 12 | -------------------------------------------------------------------------------- /examples/bdd/features/arguments_four_steps_docstring.feature: -------------------------------------------------------------------------------- 1 | Feature: Four step arguments 2 | Description for the feature 3 | 4 | Scenario: Arguments for given, when, and, then 5 | Description for the scenario 6 | 7 | Given there are 5 cucumbers 8 | """ 9 | Docstring for the step 10 | """ 11 | 12 | When I eat 3 cucumbers 13 | And I eat 2 cucumbers 14 | 15 | Then I should have 0 cucumbers 16 | -------------------------------------------------------------------------------- /examples/bdd/features/arguments_three_steps.feature: -------------------------------------------------------------------------------- 1 | Feature: Three step arguments 2 | Scenario: Arguments for given, when, then, less steps 3 | Given there are 5 cucumbers 4 | 5 | When I eat 5 cucumbers 6 | 7 | Then I should have 0 cucumbers 8 | -------------------------------------------------------------------------------- /examples/bdd/features/arguments_two_scenarios.feature: -------------------------------------------------------------------------------- 1 | Feature: Two scenarios step arguments 2 | Scenario: Arguments for given, when, then 3 | Given there are 5 cucumbers 4 | 5 | When I eat 5 cucumbers 6 | 7 | Then I should have 0 cucumbers 8 | 9 | Scenario: Arguments for given, when, and, then 10 | Given there are 5 cucumbers 11 | 12 | When I eat 3 cucumbers 13 | And I eat 2 cucumbers 14 | 15 | Then I should have 0 cucumbers 16 | -------------------------------------------------------------------------------- /examples/bdd/features/background_scenario.feature: -------------------------------------------------------------------------------- 1 | Feature: Test scenario with a background 2 | 3 | Background: Init our scenario 4 | Given I have empty step 5 | 6 | Scenario: The first scenario 7 | Then I have another empty step 8 | 9 | Scenario: The second scenario 10 | Then I have one more empty step 11 | -------------------------------------------------------------------------------- /examples/bdd/features/background_two_steps.feature: -------------------------------------------------------------------------------- 1 | Feature: Test scenario with a background with two steps 2 | Background: 3 | Given I have first empty step 4 | And I have second empty step 5 | 6 | Scenario: The scenario 7 | Then I have main step 8 | -------------------------------------------------------------------------------- /examples/bdd/features/belly.feature: -------------------------------------------------------------------------------- 1 | @smoke @test @feature:belly 2 | Feature: Belly 3 | 4 | @ok @key:value 5 | Scenario: a few cukes 6 | Given I have 42 cukes in my belly 7 | When I wait 1 hour 8 | Then my belly should growl 9 | -------------------------------------------------------------------------------- /examples/bdd/features/custom_test_case_id.feature: -------------------------------------------------------------------------------- 1 | Feature: Test dummy scenario 2 | 3 | @tc_id:my_tc_id 4 | Scenario: The scenario 5 | Given I have empty step 6 | -------------------------------------------------------------------------------- /examples/bdd/features/data_table_parameter.feature: -------------------------------------------------------------------------------- 1 | Feature: A basic test with a Data Table parameter 2 | 3 | Scenario: Test with Data Table 4 | Given a step with a data table: 5 | | key | value | 6 | | myKey | myValue | 7 | -------------------------------------------------------------------------------- /examples/bdd/features/doc_string_parameters.feature: -------------------------------------------------------------------------------- 1 | Feature: Basic test with a docstring parameter 2 | 3 | Scenario: Test with a docstring parameter 4 | Given I have a docstring parameter: 5 | """ 6 | My very long parameter 7 | With some new lines 8 | """ 9 | -------------------------------------------------------------------------------- /examples/bdd/features/dynamic_scenario_outline_names.feature: -------------------------------------------------------------------------------- 1 | Feature: Dynamic scenario outline names 2 | 3 | Scenario Outline: Test with the parameter 4 | Given It is test with parameters 5 | When I have parameter 6 | Then I emit number on level info 7 | 8 | Examples: 9 | | str | parameters | 10 | | "first" | 123 | 11 | | "second" | 12345 | 12 | -------------------------------------------------------------------------------- /examples/bdd/features/examples_tags.feature: -------------------------------------------------------------------------------- 1 | Feature: Basic test with parameters 2 | 3 | Scenario Outline: Test with different parameters 4 | Given It is test with parameters 5 | When I have parameter 6 | Then I emit number on level info 7 | 8 | @test 9 | Examples: 10 | | str | parameters | 11 | | "first" | 123 | 12 | | "second" | 12345 | 13 | | "third" | 12345678 | 14 | -------------------------------------------------------------------------------- /examples/bdd/features/failed_scenario.feature: -------------------------------------------------------------------------------- 1 | Feature: Test failed scenario 2 | 3 | Scenario: The scenario 4 | Given I have a failed step 5 | -------------------------------------------------------------------------------- /examples/bdd/features/long_step_scenario.feature: -------------------------------------------------------------------------------- 1 | Feature: Test long step scenario 2 | 3 | Scenario: The scenario 4 | Given A very long step. Seriously, this step is ridiculously long. Our users require such a long step and here it is. This is not even a half of the step, it will last really long. I believe you will get tired before you reach the end of the step. Why? Because our users send here a megabyte-length JSONs or things like that, despite our words that this is not good for user experience, since it's hard to read such a long lines on UI and for backend performance, since we use this field in full-text search. OK I'm out of thought what else I can write here, but the step must go on. Probably you will see some random typing soon to get the step longer than it's right now. Because only now we crossed a half of the length we need. Alright, here we go: 39248cht42 3x,r093mhxr0,3hr c089r3423 xk309,,r3 k302uk032 3249xul398u3 at 34r9k39489 aumvi xkr293jed0 i 93u9f32u smhf 09ktc903 a tu09r328 ef5u0fu3v 0k8utf2 u59du9v u423kuc 9f5kv 39kd3uf39 -3940u5kfu5 b3-90485l-k3f. Are you tired? I'm too, but we still need a few words at the end. 5 | -------------------------------------------------------------------------------- /examples/bdd/features/rule_description.feature: -------------------------------------------------------------------------------- 1 | Feature: Test rule keyword 2 | 3 | Rule: The first rule 4 | Description for the Rule 5 | 6 | Scenario: The first scenario 7 | Given I have empty step 8 | -------------------------------------------------------------------------------- /examples/bdd/features/rule_keyword.feature: -------------------------------------------------------------------------------- 1 | Feature: Test rule keyword 2 | 3 | Rule: The first rule 4 | Scenario: The first scenario 5 | Given I have empty step 6 | Then I have another empty step 7 | 8 | Scenario: The second scenario 9 | Given I have empty step 10 | Then I have one more empty step 11 | 12 | Rule: The second rule 13 | Scenario: The third scenario 14 | Given I have empty step 15 | Then I have one more else empty step 16 | -------------------------------------------------------------------------------- /examples/bdd/features/scenario_outline_background.feature: -------------------------------------------------------------------------------- 1 | Feature: Basic test with parameters and background 2 | 3 | Background: 4 | Given I have empty step in background 5 | 6 | Scenario Outline: Test with different parameters 7 | Given It is test with parameters 8 | When I have parameter 9 | Then I emit number on level info 10 | 11 | Examples: 12 | | str | parameters | 13 | | "first" | 123 | 14 | | "second" | 12345 | 15 | -------------------------------------------------------------------------------- /examples/bdd/features/scenario_outline_description.feature: -------------------------------------------------------------------------------- 1 | Feature: Basic test with parameters and description 2 | 3 | Scenario Outline: Test with different parameters 4 | The description for the scenario outline 5 | 6 | Given It is test with parameters 7 | When I have parameter 8 | Then I emit number on level info 9 | 10 | Examples: 11 | | str | parameters | 12 | | "first" | 123 | 13 | | "second" | 12345 | 14 | -------------------------------------------------------------------------------- /examples/bdd/features/scenario_outline_fail.feature: -------------------------------------------------------------------------------- 1 | Feature: Basic test with parameters which fails 2 | 3 | Scenario Outline: Test with different parameters failing 4 | Given It is test with parameters 5 | When I have parameter 6 | Then I emit number on level info 7 | Then I fail 8 | 9 | Examples: 10 | | str | parameters | 11 | | "first" | 123 | 12 | | "second" | 12345 | 13 | -------------------------------------------------------------------------------- /examples/bdd/features/scenario_outline_parameters.feature: -------------------------------------------------------------------------------- 1 | Feature: Basic test with parameters 2 | 3 | Scenario Outline: Test with different parameters 4 | Given It is test with parameters 5 | When I have parameter 6 | Then I emit number on level info 7 | 8 | Examples: 9 | | str | parameters | 10 | | "first" | 123 | 11 | | "second" | 12345 | 12 | | "third" | 12345678 | 13 | -------------------------------------------------------------------------------- /examples/bdd/features/scenario_outline_test_case_id.feature: -------------------------------------------------------------------------------- 1 | Feature: Basic test with parameters 2 | 3 | @tc_id:outline_tc_id 4 | Scenario Outline: Test with different parameters 5 | Given It is test with parameters 6 | When I have parameter 7 | Then I emit number on level info 8 | 9 | Examples: 10 | | str | parameters | 11 | | "first" | 123 | 12 | -------------------------------------------------------------------------------- /examples/bdd/step_defs/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | -------------------------------------------------------------------------------- /examples/bdd/step_defs/custom_test_case_id_steps.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import logging 16 | 17 | from pytest_bdd import given, scenarios 18 | 19 | # Import the scenario from the feature file 20 | scenarios("../features/custom_test_case_id.feature") 21 | 22 | LOGGER = logging.getLogger(__name__) 23 | 24 | 25 | @given("I have empty step") 26 | def step_with_custom_test_case_id(): 27 | LOGGER.info("I have empty step") 28 | -------------------------------------------------------------------------------- /examples/bdd/step_defs/data_table_parameter_steps.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import logging 16 | from typing import Dict 17 | 18 | from pytest_bdd import given, scenarios 19 | 20 | # Import the scenario from the feature file 21 | scenarios("../features/data_table_parameter.feature") 22 | 23 | 24 | LOGGER = logging.getLogger(__name__) 25 | 26 | 27 | @given("a step with a data table:") 28 | def step_with_data_table(datatable: Dict[str, str]) -> None: 29 | """Step that receives a data table and logs its content. 30 | 31 | :param datatable: Data table from the feature file 32 | """ 33 | LOGGER.info("Data table content: %s", datatable) 34 | -------------------------------------------------------------------------------- /examples/bdd/step_defs/doc_string_parameters_steps.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import logging 16 | 17 | from pytest_bdd import given, scenarios 18 | 19 | # Import the scenario from the feature file 20 | scenarios("../features/doc_string_parameters.feature") 21 | 22 | 23 | LOGGER = logging.getLogger(__name__) 24 | 25 | 26 | @given("I have a docstring parameter:") 27 | def step_with_docstring(docstring: str) -> None: 28 | """Step that receives a docstring and logs its content. 29 | 30 | :param docstring: Multi-line docstring from the feature file 31 | """ 32 | LOGGER.info("Docstring content: %s", docstring) 33 | -------------------------------------------------------------------------------- /examples/bdd/step_defs/example_tags_steps.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import logging 16 | 17 | from pytest_bdd import given, parsers, scenarios, then, when 18 | 19 | # Import the scenario from the feature file 20 | scenarios("../features/examples_tags.feature") 21 | 22 | 23 | LOGGER = logging.getLogger(__name__) 24 | 25 | 26 | @given("It is test with parameters") 27 | def step_with_parameters(): 28 | LOGGER.info("It is test with parameters") 29 | 30 | 31 | @when(parsers.parse('I have parameter "{parameter}"')) 32 | def have_parameter_str(parameter: str): 33 | LOGGER.info("String parameter %s", parameter) 34 | 35 | 36 | @then(parsers.parse("I emit number {parameters:d} on level info")) 37 | def emit_number_info(parameters): 38 | LOGGER.info("Test with parameters: %d", parameters) 39 | -------------------------------------------------------------------------------- /examples/bdd/step_defs/long_step_scenario_steps.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import logging 16 | 17 | from pytest_bdd import given, scenarios 18 | 19 | # Import the scenario from the feature file 20 | scenarios("../features/long_step_scenario.feature") 21 | 22 | 23 | LOGGER = logging.getLogger(__name__) 24 | 25 | 26 | @given( 27 | "A very long step. Seriously, this step is ridiculously long. Our users require such a long step and here it is. This is not even a half of the step, it will last really long. I believe you will get tired before you reach the end of the step. Why? Because our users send here a megabyte-length JSONs or things like that, despite our words that this is not good for user experience, since it's hard to read such a long lines on UI and for backend performance, since we use this field in full-text search. OK I'm out of thought what else I can write here, but the step must go on. Probably you will see some random typing soon to get the step longer than it's right now. Because only now we crossed a half of the length we need. Alright, here we go: 39248cht42 3x,r093mhxr0,3hr c089r3423 xk309,,r3 k302uk032 3249xul398u3 at 34r9k39489 aumvi xkr293jed0 i 93u9f32u smhf 09ktc903 a tu09r328 ef5u0fu3v 0k8utf2 u59du9v u423kuc 9f5kv 39kd3uf39 -3940u5kfu5 b3-90485l-k3f. Are you tired? I'm too, but we still need a few words at the end." # noqa: E501 28 | ) 29 | def step_with_long_text(): 30 | LOGGER.info("Step with extremely long text executed successfully") 31 | -------------------------------------------------------------------------------- /examples/bdd/step_defs/scenario_outline_background_steps.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import logging 16 | 17 | from pytest_bdd import given, parsers, scenarios, then, when 18 | 19 | # Import the scenario from the feature file 20 | scenarios("../features/scenario_outline_background.feature") 21 | 22 | 23 | LOGGER = logging.getLogger(__name__) 24 | 25 | 26 | @given("I have empty step in background") 27 | def empty_step(): 28 | """Empty step implementation.""" 29 | pass 30 | 31 | 32 | @given("It is test with parameters") 33 | def step_with_parameters(): 34 | LOGGER.info("It is test with parameters") 35 | 36 | 37 | @when(parsers.parse('I have parameter "{parameter}"')) 38 | def have_parameter_str(parameter: str): 39 | LOGGER.info("String parameter %s", parameter) 40 | 41 | 42 | @then(parsers.parse("I emit number {parameters:d} on level info")) 43 | def emit_number_info(parameters): 44 | LOGGER.info("Test with parameters: %d", parameters) 45 | -------------------------------------------------------------------------------- /examples/bdd/step_defs/scenario_outline_description_steps.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import logging 16 | 17 | from pytest_bdd import given, parsers, scenarios, then, when 18 | 19 | # Import the scenario from the feature file 20 | scenarios("../features/scenario_outline_description.feature") 21 | 22 | 23 | LOGGER = logging.getLogger(__name__) 24 | 25 | 26 | @given("It is test with parameters") 27 | def step_with_parameters(): 28 | LOGGER.info("It is test with parameters") 29 | 30 | 31 | @when(parsers.parse('I have parameter "{parameter}"')) 32 | def have_parameter_str(parameter: str): 33 | LOGGER.info("String parameter %s", parameter) 34 | 35 | 36 | @then(parsers.parse("I emit number {parameters:d} on level info")) 37 | def emit_number_info(parameters): 38 | LOGGER.info("Test with parameters: %d", parameters) 39 | -------------------------------------------------------------------------------- /examples/bdd/step_defs/scenario_outline_fail_steps.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import logging 16 | 17 | from pytest_bdd import given, parsers, scenarios, then, when 18 | 19 | # Import the scenario from the feature file 20 | scenarios("../features/scenario_outline_fail.feature") 21 | 22 | 23 | LOGGER = logging.getLogger(__name__) 24 | 25 | 26 | @given("It is test with parameters") 27 | def step_with_parameters(): 28 | LOGGER.info("It is test with parameters") 29 | 30 | 31 | @when(parsers.parse('I have parameter "{parameter}"')) 32 | def have_parameter_str(parameter: str): 33 | LOGGER.info("String parameter %s", parameter) 34 | 35 | 36 | @then(parsers.parse("I emit number {parameters:d} on level info")) 37 | def emit_number_info(parameters): 38 | LOGGER.info("Test with parameters: %d", parameters) 39 | 40 | 41 | @then("I fail") 42 | def fail_step(): 43 | raise AssertionError("This step always fails") 44 | -------------------------------------------------------------------------------- /examples/bdd/step_defs/scenario_outline_name_steps.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import logging 16 | 17 | from pytest_bdd import given, parsers, scenarios, then, when 18 | 19 | # Import the scenario from the feature file 20 | scenarios("../features/dynamic_scenario_outline_names.feature") 21 | 22 | 23 | LOGGER = logging.getLogger(__name__) 24 | 25 | 26 | @given("It is test with parameters") 27 | def step_with_parameters(): 28 | LOGGER.info("It is test with parameters") 29 | 30 | 31 | @when(parsers.parse('I have parameter "{parameter}"')) 32 | def have_parameter_str(parameter: str): 33 | LOGGER.info("String parameter %s", parameter) 34 | 35 | 36 | @then(parsers.parse("I emit number {parameters:d} on level info")) 37 | def emit_number_info(parameters): 38 | LOGGER.info("Test with parameters: %d", parameters) 39 | -------------------------------------------------------------------------------- /examples/bdd/step_defs/scenario_outline_parameters_steps.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import logging 16 | 17 | from pytest_bdd import given, parsers, scenarios, then, when 18 | 19 | # Import the scenario from the feature file 20 | scenarios("../features/scenario_outline_parameters.feature") 21 | 22 | 23 | LOGGER = logging.getLogger(__name__) 24 | 25 | 26 | @given("It is test with parameters") 27 | def step_with_parameters(): 28 | LOGGER.info("It is test with parameters") 29 | 30 | 31 | @when(parsers.parse('I have parameter "{parameter}"')) 32 | def have_parameter_str(parameter: str): 33 | LOGGER.info("String parameter %s", parameter) 34 | 35 | 36 | @then(parsers.parse("I emit number {parameters:d} on level info")) 37 | def emit_number_info(parameters): 38 | LOGGER.info("Test with parameters: %d", parameters) 39 | -------------------------------------------------------------------------------- /examples/bdd/step_defs/scenario_outline_test_case_id_steps.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import logging 16 | 17 | from pytest_bdd import given, parsers, scenarios, then, when 18 | 19 | # Import the scenario from the feature file 20 | scenarios("../features/scenario_outline_test_case_id.feature") 21 | 22 | LOGGER = logging.getLogger(__name__) 23 | 24 | 25 | @given("It is test with parameters") 26 | def step_with_parameters(): 27 | LOGGER.info("It is test with parameters") 28 | 29 | 30 | @when(parsers.parse('I have parameter "{parameter}"')) 31 | def have_parameter_str(parameter: str): 32 | LOGGER.info("String parameter %s", parameter) 33 | 34 | 35 | @then(parsers.parse("I emit number {parameters:d} on level info")) 36 | def emit_number_info(parameters): 37 | LOGGER.info("Test with parameters: %d", parameters) 38 | -------------------------------------------------------------------------------- /examples/bdd/step_defs/test_arguments.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from pytest_bdd import given, parsers, scenarios, then, when 16 | 17 | scenarios("../features/arguments_four_steps.feature") 18 | 19 | 20 | @given(parsers.parse("there are {start:d} cucumbers"), target_fixture="cucumbers") 21 | def given_cucumbers(start): 22 | return {"start": start, "eat": 0} 23 | 24 | 25 | @when(parsers.parse("I eat {eat:d} cucumbers")) 26 | def eat_cucumbers(cucumbers, eat): 27 | cucumbers["eat"] += eat 28 | 29 | 30 | @then(parsers.parse("I should have {left:d} cucumbers")) 31 | def should_have_left_cucumbers(cucumbers, left): 32 | assert cucumbers["start"] - cucumbers["eat"] == left 33 | -------------------------------------------------------------------------------- /examples/bdd/step_defs/test_arguments_description.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from pytest_bdd import given, parsers, scenarios, then, when 16 | 17 | scenarios("../features/arguments_four_steps_description.feature") 18 | 19 | 20 | @given(parsers.parse("there are {start:d} cucumbers"), target_fixture="cucumbers") 21 | def given_cucumbers(start): 22 | return {"start": start, "eat": 0} 23 | 24 | 25 | @when(parsers.parse("I eat {eat:d} cucumbers")) 26 | def eat_cucumbers(cucumbers, eat): 27 | cucumbers["eat"] += eat 28 | 29 | 30 | @then(parsers.parse("I should have {left:d} cucumbers")) 31 | def should_have_left_cucumbers(cucumbers, left): 32 | assert cucumbers["start"] - cucumbers["eat"] == left 33 | -------------------------------------------------------------------------------- /examples/bdd/step_defs/test_arguments_two_features.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from pytest_bdd import given, parsers, scenarios, then, when 16 | 17 | scenarios("../features/arguments_four_steps.feature", "../features/arguments_three_steps.feature") 18 | 19 | 20 | @given(parsers.parse("there are {start:d} cucumbers"), target_fixture="cucumbers") 21 | def given_cucumbers(start): 22 | return {"start": start, "eat": 0} 23 | 24 | 25 | @when(parsers.parse("I eat {eat:d} cucumbers")) 26 | def eat_cucumbers(cucumbers, eat): 27 | cucumbers["eat"] += eat 28 | 29 | 30 | @then(parsers.parse("I should have {left:d} cucumbers")) 31 | def should_have_left_cucumbers(cucumbers, left): 32 | assert cucumbers["start"] - cucumbers["eat"] == left 33 | -------------------------------------------------------------------------------- /examples/bdd/step_defs/test_arguments_two_scenarios.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from pytest_bdd import given, parsers, scenarios, then, when 16 | 17 | scenarios("../features/arguments_two_scenarios.feature") 18 | 19 | 20 | @given(parsers.parse("there are {start:d} cucumbers"), target_fixture="cucumbers") 21 | def given_cucumbers(start): 22 | return {"start": start, "eat": 0} 23 | 24 | 25 | @when(parsers.parse("I eat {eat:d} cucumbers")) 26 | def eat_cucumbers(cucumbers, eat): 27 | cucumbers["eat"] += eat 28 | 29 | 30 | @then(parsers.parse("I should have {left:d} cucumbers")) 31 | def should_have_left_cucumbers(cucumbers, left): 32 | assert cucumbers["start"] - cucumbers["eat"] == left 33 | -------------------------------------------------------------------------------- /examples/bdd/step_defs/test_background.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from pytest_bdd import given, scenarios, then 16 | 17 | scenarios("../features/background_scenario.feature") 18 | 19 | 20 | @given("I have empty step") 21 | def empty_step(): 22 | pass 23 | 24 | 25 | @then("I have another empty step") 26 | def another_empty_step(): 27 | pass 28 | 29 | 30 | @then("I have one more empty step") 31 | def one_more_empty_step(): 32 | pass 33 | -------------------------------------------------------------------------------- /examples/bdd/step_defs/test_background_two_steps.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from pytest_bdd import given, scenarios, then 16 | 17 | scenarios("../features/background_two_steps.feature") 18 | 19 | 20 | @given("I have first empty step") 21 | def first_empty_step(): 22 | """First empty step implementation.""" 23 | pass 24 | 25 | 26 | @given("I have second empty step") 27 | def second_empty_step(): 28 | """Second empty step implementation.""" 29 | pass 30 | 31 | 32 | @then("I have main step") 33 | def main_step(): 34 | """Main step implementation.""" 35 | pass 36 | -------------------------------------------------------------------------------- /examples/bdd/step_defs/test_belly.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from pytest_bdd import given, parsers, scenarios, then, when 16 | 17 | scenarios("../features/belly.feature") 18 | 19 | 20 | @given(parsers.parse("I have {start:d} cukes in my belly"), target_fixture="cucumbers") 21 | def given_cucumbers(start): 22 | return {"start": start, "wait": 0} 23 | 24 | 25 | @when(parsers.parse("I wait {hours:d} hour")) 26 | def then_wait(cucumbers, hours): 27 | cucumbers["wait"] += hours 28 | 29 | 30 | @then("my belly should growl") 31 | def assert_growl(cucumbers): 32 | assert cucumbers["start"] == cucumbers["wait"] * 42 33 | -------------------------------------------------------------------------------- /examples/bdd/step_defs/test_failed_step.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from pytest_bdd import given, scenarios 16 | 17 | scenarios("../features/failed_scenario.feature") 18 | 19 | 20 | @given("I have a failed step") 21 | def failed_step(): 22 | assert False 23 | -------------------------------------------------------------------------------- /examples/bdd/step_defs/test_rule_description_steps.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Rule keyword test module.""" 16 | 17 | from pytest_bdd import given, scenarios 18 | 19 | scenarios("../features/rule_description.feature") 20 | 21 | 22 | @given("I have empty step") 23 | def empty_step(): 24 | """Empty step implementation.""" 25 | pass 26 | -------------------------------------------------------------------------------- /examples/bdd/step_defs/test_rule_steps.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Rule keyword test module.""" 16 | from pytest_bdd import given, scenarios, then 17 | 18 | scenarios("../features/rule_keyword.feature") 19 | 20 | 21 | @given("I have empty step") 22 | def empty_step(): 23 | """Empty step implementation.""" 24 | pass 25 | 26 | 27 | @then("I have another empty step") 28 | def another_empty_step(): 29 | """Another empty step implementation.""" 30 | pass 31 | 32 | 33 | @then("I have one more empty step") 34 | def one_more_empty_step(): 35 | """One more empty step implementation.""" 36 | pass 37 | 38 | 39 | @then("I have one more else empty step") 40 | def one_more_else_empty_step(): 41 | """One more else empty step implementation.""" 42 | pass 43 | -------------------------------------------------------------------------------- /examples/custom_name/test_custom_name_args.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import pytest 15 | 16 | TEST_NAME_ARGS = "Test name by mark" 17 | 18 | 19 | @pytest.mark.name(TEST_NAME_ARGS) 20 | def test_name_by_mark_args(): 21 | """Simple example test with the name comes from Pytest mark.""" 22 | assert True 23 | -------------------------------------------------------------------------------- /examples/custom_name/test_custom_name_empty.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import pytest 15 | 16 | TEST_NAME_EMPTY = "examples/custom_name/test_custom_name_empty.py::test_name_by_mark_empty" 17 | 18 | 19 | @pytest.mark.name() 20 | def test_name_by_mark_empty(): 21 | """Simple example test with the name comes from Pytest mark.""" 22 | assert True 23 | -------------------------------------------------------------------------------- /examples/custom_name/test_custom_name_kwargs.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import pytest 15 | 16 | TEST_NAME_KWARGS = "Test name by mark, kwargs" 17 | 18 | 19 | @pytest.mark.name(name=TEST_NAME_KWARGS) 20 | def test_name_by_mark_kwargs(): 21 | """Simple example test with the name comes from Pytest mark.""" 22 | assert True 23 | -------------------------------------------------------------------------------- /examples/empty/README.txt: -------------------------------------------------------------------------------- 1 | A placeholder file for git 2 | -------------------------------------------------------------------------------- /examples/fixtures/class_fixture_return/conftest.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from unittest import mock 16 | 17 | import pytest 18 | 19 | 20 | @pytest.fixture(scope="class") 21 | def class_fixture_return_config(): 22 | print("setup") 23 | return mock.Mock() 24 | -------------------------------------------------------------------------------- /examples/fixtures/class_fixture_return/test_fixture_class_setup.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | # Licensed under the Apache License, Version 2.0 (the "License"); 16 | # you may not use this file except in compliance with the License. 17 | # You may obtain a copy of the License at 18 | # 19 | # https://www.apache.org/licenses/LICENSE-2.0 20 | # 21 | # Unless required by applicable law or agreed to in writing, software 22 | # distributed under the License is distributed on an "AS IS" BASIS, 23 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24 | # See the License for the specific language governing permissions and 25 | # limitations under the License. 26 | 27 | 28 | class TestClassOne: 29 | def test_fixture_class_setup_first(self, class_fixture_return_config): 30 | assert class_fixture_return_config is not None 31 | 32 | def test_fixture_class_setup_second(self, class_fixture_return_config): 33 | assert class_fixture_return_config is not None 34 | 35 | 36 | class TestClassTwo: 37 | def test_fixture_class_setup_forth(self, class_fixture_return_config): 38 | assert class_fixture_return_config is not None 39 | 40 | def test_fixture_class_setup_fifth(self, class_fixture_return_config): 41 | assert class_fixture_return_config is not None 42 | -------------------------------------------------------------------------------- /examples/fixtures/module_fixture_return/conftest.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from unittest import mock 16 | 17 | import pytest 18 | 19 | 20 | @pytest.fixture(scope="module") 21 | def module_fixture_return_config(): 22 | print("setup") 23 | return mock.Mock() 24 | -------------------------------------------------------------------------------- /examples/fixtures/module_fixture_return/test_fixture_module_setup.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | # Licensed under the Apache License, Version 2.0 (the "License"); 16 | # you may not use this file except in compliance with the License. 17 | # You may obtain a copy of the License at 18 | # 19 | # https://www.apache.org/licenses/LICENSE-2.0 20 | # 21 | # Unless required by applicable law or agreed to in writing, software 22 | # distributed under the License is distributed on an "AS IS" BASIS, 23 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24 | # See the License for the specific language governing permissions and 25 | # limitations under the License. 26 | 27 | 28 | def test_fixture_module_setup_first(module_fixture_return_config): 29 | assert module_fixture_return_config is not None 30 | 31 | 32 | def test_fixture_module_setup_second(module_fixture_return_config): 33 | assert module_fixture_return_config is not None 34 | -------------------------------------------------------------------------------- /examples/fixtures/package_fixture_return/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | -------------------------------------------------------------------------------- /examples/fixtures/package_fixture_return/conftest.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from unittest import mock 16 | 17 | import pytest 18 | 19 | 20 | @pytest.fixture(scope="package") 21 | def package_fixture_return_config(): 22 | print("setup") 23 | return mock.Mock() 24 | -------------------------------------------------------------------------------- /examples/fixtures/package_fixture_return/test_fixture_package_setup_first.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | # Licensed under the Apache License, Version 2.0 (the "License"); 16 | # you may not use this file except in compliance with the License. 17 | # You may obtain a copy of the License at 18 | # 19 | # https://www.apache.org/licenses/LICENSE-2.0 20 | # 21 | # Unless required by applicable law or agreed to in writing, software 22 | # distributed under the License is distributed on an "AS IS" BASIS, 23 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24 | # See the License for the specific language governing permissions and 25 | # limitations under the License. 26 | 27 | 28 | def test_fixture_package_setup_first(package_fixture_return_config): 29 | assert package_fixture_return_config is not None 30 | -------------------------------------------------------------------------------- /examples/fixtures/package_fixture_return/test_fixture_package_setup_second.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | # Licensed under the Apache License, Version 2.0 (the "License"); 16 | # you may not use this file except in compliance with the License. 17 | # You may obtain a copy of the License at 18 | # 19 | # https://www.apache.org/licenses/LICENSE-2.0 20 | # 21 | # Unless required by applicable law or agreed to in writing, software 22 | # distributed under the License is distributed on an "AS IS" BASIS, 23 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24 | # See the License for the specific language governing permissions and 25 | # limitations under the License. 26 | 27 | 28 | def test_fixture_package_setup_second(package_fixture_return_config): 29 | assert package_fixture_return_config is not None 30 | -------------------------------------------------------------------------------- /examples/fixtures/session_fixture_return/conftest.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from unittest import mock 16 | 17 | import pytest 18 | 19 | 20 | @pytest.fixture(scope="session") 21 | def session_fixture_return_config(): 22 | print("setup") 23 | return mock.Mock() 24 | -------------------------------------------------------------------------------- /examples/fixtures/session_fixture_return/test_fixture_session_setup_first.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | # Licensed under the Apache License, Version 2.0 (the "License"); 16 | # you may not use this file except in compliance with the License. 17 | # You may obtain a copy of the License at 18 | # 19 | # https://www.apache.org/licenses/LICENSE-2.0 20 | # 21 | # Unless required by applicable law or agreed to in writing, software 22 | # distributed under the License is distributed on an "AS IS" BASIS, 23 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24 | # See the License for the specific language governing permissions and 25 | # limitations under the License. 26 | 27 | 28 | def test_fixture_session_setup_first(session_fixture_return_config): 29 | assert session_fixture_return_config is not None 30 | -------------------------------------------------------------------------------- /examples/fixtures/session_fixture_return/test_fixture_session_setup_second.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | # Licensed under the Apache License, Version 2.0 (the "License"); 16 | # you may not use this file except in compliance with the License. 17 | # You may obtain a copy of the License at 18 | # 19 | # https://www.apache.org/licenses/LICENSE-2.0 20 | # 21 | # Unless required by applicable law or agreed to in writing, software 22 | # distributed under the License is distributed on an "AS IS" BASIS, 23 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24 | # See the License for the specific language governing permissions and 25 | # limitations under the License. 26 | 27 | 28 | def test_fixture_session_setup_second(session_fixture_return_config): 29 | assert session_fixture_return_config is not None 30 | -------------------------------------------------------------------------------- /examples/fixtures/test_failure_fixture_teardown/conftest.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import logging 16 | from unittest import mock 17 | 18 | import pytest 19 | from reportportal_client import RPLogger 20 | 21 | LOGGER = logging.getLogger(__name__) 22 | LOGGER.setLevel(logging.DEBUG) 23 | logging.setLoggerClass(RPLogger) 24 | 25 | LOG_MESSAGE_BEFORE_YIELD = "Log message before yield and test failure" 26 | LOG_MESSAGE_TEARDOWN = "Log message for teardown after test failure" 27 | 28 | 29 | @pytest.fixture 30 | def test_failure_fixture_teardown_config(): 31 | logging.error(LOG_MESSAGE_BEFORE_YIELD) 32 | yield mock.Mock() 33 | logging.error(LOG_MESSAGE_TEARDOWN) 34 | -------------------------------------------------------------------------------- /examples/fixtures/test_failure_fixture_teardown/test_failure_fixture_teardown.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | # Licensed under the Apache License, Version 2.0 (the "License"); 16 | # you may not use this file except in compliance with the License. 17 | # You may obtain a copy of the License at 18 | # 19 | # https://www.apache.org/licenses/LICENSE-2.0 20 | # 21 | # Unless required by applicable law or agreed to in writing, software 22 | # distributed under the License is distributed on an "AS IS" BASIS, 23 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24 | # See the License for the specific language governing permissions and 25 | # limitations under the License. 26 | 27 | 28 | def test_failure_fixture_teardown(test_failure_fixture_teardown_config): 29 | assert test_failure_fixture_teardown_config is None 30 | -------------------------------------------------------------------------------- /examples/fixtures/test_fixture_exit/test_fixture_exit.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import pytest 16 | 17 | 18 | @pytest.fixture 19 | def fixture_demo(): 20 | pytest.exit("Some Message") 21 | 22 | 23 | def test_exit(fixture_demo): 24 | assert True 25 | -------------------------------------------------------------------------------- /examples/fixtures/test_fixture_return_none/conftest.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import logging 16 | 17 | import pytest 18 | from reportportal_client import RPLogger 19 | 20 | LOGGER = logging.getLogger(__name__) 21 | LOGGER.setLevel(logging.DEBUG) 22 | logging.setLoggerClass(RPLogger) 23 | 24 | LOG_MESSAGE_SETUP = "Log message for setup and return None" 25 | 26 | 27 | @pytest.fixture 28 | def test_fixture_return_none_config(): 29 | LOGGER.warning(LOG_MESSAGE_SETUP) 30 | -------------------------------------------------------------------------------- /examples/fixtures/test_fixture_return_none/test_fixture_return_none.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | # Licensed under the Apache License, Version 2.0 (the "License"); 16 | # you may not use this file except in compliance with the License. 17 | # You may obtain a copy of the License at 18 | # 19 | # https://www.apache.org/licenses/LICENSE-2.0 20 | # 21 | # Unless required by applicable law or agreed to in writing, software 22 | # distributed under the License is distributed on an "AS IS" BASIS, 23 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24 | # See the License for the specific language governing permissions and 25 | # limitations under the License. 26 | 27 | 28 | def test_fixture_setup_none(test_fixture_return_none_config): 29 | assert test_fixture_return_none_config is None 30 | -------------------------------------------------------------------------------- /examples/fixtures/test_fixture_setup/conftest.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import logging 16 | from unittest import mock 17 | 18 | import pytest 19 | from reportportal_client import RPLogger 20 | 21 | LOGGER = logging.getLogger(__name__) 22 | LOGGER.setLevel(logging.DEBUG) 23 | logging.setLoggerClass(RPLogger) 24 | 25 | LOG_MESSAGE_SETUP = "Log message for setup" 26 | 27 | 28 | @pytest.fixture 29 | def test_fixture_setup_config(): 30 | logging.error(LOG_MESSAGE_SETUP) 31 | return mock.Mock() 32 | -------------------------------------------------------------------------------- /examples/fixtures/test_fixture_setup/test_fixture_setup.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | # Licensed under the Apache License, Version 2.0 (the "License"); 16 | # you may not use this file except in compliance with the License. 17 | # You may obtain a copy of the License at 18 | # 19 | # https://www.apache.org/licenses/LICENSE-2.0 20 | # 21 | # Unless required by applicable law or agreed to in writing, software 22 | # distributed under the License is distributed on an "AS IS" BASIS, 23 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24 | # See the License for the specific language governing permissions and 25 | # limitations under the License. 26 | 27 | 28 | def test_fixture_setup(test_fixture_setup_config): 29 | assert test_fixture_setup_config is not None 30 | -------------------------------------------------------------------------------- /examples/fixtures/test_fixture_setup_failure/conftest.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import logging 16 | 17 | import pytest 18 | from reportportal_client import RPLogger 19 | 20 | LOGGER = logging.getLogger(__name__) 21 | LOGGER.setLevel(logging.DEBUG) 22 | logging.setLoggerClass(RPLogger) 23 | 24 | LOG_MESSAGE_SETUP = "Log message for setup failure" 25 | 26 | 27 | @pytest.fixture 28 | def test_fixture_setup_failure_config(): 29 | logging.error(LOG_MESSAGE_SETUP) 30 | raise Exception("Fixture setup failed") 31 | -------------------------------------------------------------------------------- /examples/fixtures/test_fixture_setup_failure/test_fixture_setup_failure.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | # Licensed under the Apache License, Version 2.0 (the "License"); 16 | # you may not use this file except in compliance with the License. 17 | # You may obtain a copy of the License at 18 | # 19 | # https://www.apache.org/licenses/LICENSE-2.0 20 | # 21 | # Unless required by applicable law or agreed to in writing, software 22 | # distributed under the License is distributed on an "AS IS" BASIS, 23 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24 | # See the License for the specific language governing permissions and 25 | # limitations under the License. 26 | 27 | import logging 28 | 29 | from reportportal_client import RPLogger 30 | 31 | LOGGER = logging.getLogger(__name__) 32 | LOGGER.setLevel(logging.DEBUG) 33 | logging.setLoggerClass(RPLogger) 34 | 35 | LOG_MESSAGE_TEST = "Log message for test of setup failure" 36 | 37 | 38 | def test_fixture_setup_failure(test_fixture_setup_failure_config): 39 | logging.error(LOG_MESSAGE_TEST) 40 | assert test_fixture_setup_failure_config is not None 41 | -------------------------------------------------------------------------------- /examples/fixtures/test_fixture_skipped/test_fixture_skipped.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import pytest 16 | 17 | 18 | @pytest.fixture(scope="session") 19 | def base_fixture(): 20 | return False 21 | 22 | 23 | @pytest.fixture() 24 | def skip_fixture(base_fixture): 25 | if not base_fixture: 26 | pytest.skip("Skip if base condition is false") 27 | 28 | 29 | def test_will_skip(skip_fixture): 30 | pass 31 | -------------------------------------------------------------------------------- /examples/fixtures/test_fixture_teardown/conftest.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import logging 16 | from unittest import mock 17 | 18 | import pytest 19 | from reportportal_client import RPLogger 20 | 21 | LOGGER = logging.getLogger(__name__) 22 | LOGGER.setLevel(logging.DEBUG) 23 | logging.setLoggerClass(RPLogger) 24 | 25 | LOG_MESSAGE_BEFORE_YIELD = "Log message before yield" 26 | LOG_MESSAGE_TEARDOWN = "Log message for teardown" 27 | 28 | 29 | @pytest.fixture 30 | def test_fixture_teardown_config(): 31 | logging.error(LOG_MESSAGE_BEFORE_YIELD) 32 | yield mock.Mock() 33 | logging.error(LOG_MESSAGE_TEARDOWN) 34 | -------------------------------------------------------------------------------- /examples/fixtures/test_fixture_teardown/test_fixture_teardown.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | # Licensed under the Apache License, Version 2.0 (the "License"); 16 | # you may not use this file except in compliance with the License. 17 | # You may obtain a copy of the License at 18 | # 19 | # https://www.apache.org/licenses/LICENSE-2.0 20 | # 21 | # Unless required by applicable law or agreed to in writing, software 22 | # distributed under the License is distributed on an "AS IS" BASIS, 23 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24 | # See the License for the specific language governing permissions and 25 | # limitations under the License. 26 | 27 | from time import sleep 28 | 29 | 30 | def test_fixture_teardown(test_fixture_teardown_config): 31 | sleep(0.001) 32 | assert test_fixture_teardown_config is not None 33 | -------------------------------------------------------------------------------- /examples/fixtures/test_fixture_teardown_failure/conftest.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import logging 16 | from unittest import mock 17 | 18 | import pytest 19 | from reportportal_client import RPLogger 20 | 21 | LOGGER = logging.getLogger(__name__) 22 | LOGGER.setLevel(logging.DEBUG) 23 | logging.setLoggerClass(RPLogger) 24 | 25 | LOG_MESSAGE_BEFORE_YIELD = "Log message before yield and failure" 26 | LOG_MESSAGE_TEARDOWN = "Log message for failure teardown" 27 | 28 | 29 | @pytest.fixture 30 | def test_fixture_teardown_failure_config(): 31 | logging.error(LOG_MESSAGE_BEFORE_YIELD) 32 | yield mock.Mock() 33 | logging.error(LOG_MESSAGE_TEARDOWN) 34 | raise Exception("Fixture teardown failed") 35 | -------------------------------------------------------------------------------- /examples/fixtures/test_fixture_teardown_failure/test_fixture_teardown_failure.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | # Licensed under the Apache License, Version 2.0 (the "License"); 16 | # you may not use this file except in compliance with the License. 17 | # You may obtain a copy of the License at 18 | # 19 | # https://www.apache.org/licenses/LICENSE-2.0 20 | # 21 | # Unless required by applicable law or agreed to in writing, software 22 | # distributed under the License is distributed on an "AS IS" BASIS, 23 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24 | # See the License for the specific language governing permissions and 25 | # limitations under the License. 26 | 27 | from time import sleep 28 | 29 | 30 | def test_fixture_teardown_failure(test_fixture_teardown_failure_config): 31 | sleep(0.001) 32 | assert test_fixture_teardown_failure_config is not None 33 | -------------------------------------------------------------------------------- /examples/fixtures/test_fixture_yield_none/conftest.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import logging 16 | 17 | import pytest 18 | from reportportal_client import RPLogger 19 | 20 | LOGGER = logging.getLogger(__name__) 21 | LOGGER.setLevel(logging.DEBUG) 22 | logging.setLoggerClass(RPLogger) 23 | 24 | LOG_MESSAGE_SETUP = "Log message for setup and yield None" 25 | 26 | 27 | @pytest.fixture 28 | def test_fixture_yield_none_config(): 29 | LOGGER.warning(LOG_MESSAGE_SETUP) 30 | yield None 31 | -------------------------------------------------------------------------------- /examples/fixtures/test_fixture_yield_none/test_fixture_yield_none.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | # Licensed under the Apache License, Version 2.0 (the "License"); 16 | # you may not use this file except in compliance with the License. 17 | # You may obtain a copy of the License at 18 | # 19 | # https://www.apache.org/licenses/LICENSE-2.0 20 | # 21 | # Unless required by applicable law or agreed to in writing, software 22 | # distributed under the License is distributed on an "AS IS" BASIS, 23 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24 | # See the License for the specific language governing permissions and 25 | # limitations under the License. 26 | 27 | 28 | def test_fixture_yield_none(test_fixture_yield_none_config): 29 | assert test_fixture_yield_none_config is None 30 | -------------------------------------------------------------------------------- /examples/hierarchy/another_inner/test_another_inner_simple.py: -------------------------------------------------------------------------------- 1 | """Simple example test.""" 2 | 3 | 4 | def test_simple(): 5 | """Simple example test.""" 6 | assert True 7 | -------------------------------------------------------------------------------- /examples/hierarchy/inner/test_inner_simple.py: -------------------------------------------------------------------------------- 1 | """Simple example test.""" 2 | 3 | 4 | def test_simple(): 5 | """Simple example test.""" 6 | assert True 7 | -------------------------------------------------------------------------------- /examples/hierarchy/test_in_class.py: -------------------------------------------------------------------------------- 1 | """A simple example test in a class.""" 2 | 3 | 4 | class Tests: 5 | def test_in_class(self): 6 | """ 7 | This is my test inside `Tests` class 8 | """ 9 | assert True 10 | -------------------------------------------------------------------------------- /examples/hierarchy/test_in_class_in_class.py: -------------------------------------------------------------------------------- 1 | """A simple example test in a class in a class.""" 2 | 3 | 4 | class Tests: 5 | class Test: 6 | def test_in_class_in_class(self): 7 | """ 8 | This is my test inside `Test` class 9 | """ 10 | assert True 11 | -------------------------------------------------------------------------------- /examples/params/test_binary_symbol_in_parameters.py: -------------------------------------------------------------------------------- 1 | """A simple example test with different parameter types.""" 2 | 3 | import pytest 4 | 5 | BINARY_TEXT = "Some text with binary symbol \0" 6 | 7 | 8 | @pytest.mark.parametrize(["text"], [[BINARY_TEXT]]) 9 | def test_in_class_parameterized(text): 10 | """ 11 | This is my test with different parameter types. 12 | """ 13 | assert text == BINARY_TEXT 14 | assert text != BINARY_TEXT.replace("\0", "\\0") 15 | -------------------------------------------------------------------------------- /examples/params/test_different_parameter_types.py: -------------------------------------------------------------------------------- 1 | """A simple example test with different parameter types.""" 2 | 3 | import pytest 4 | 5 | 6 | @pytest.mark.parametrize(["integer", "floating_point", "boolean", "none"], [(1, 1.5, True, None)]) 7 | def test_in_class_parameterized(integer, floating_point, boolean, none): 8 | """ 9 | This is my test with different parameter types. 10 | """ 11 | assert True 12 | -------------------------------------------------------------------------------- /examples/params/test_in_class_parameterized.py: -------------------------------------------------------------------------------- 1 | """A simple example test in a class with a parameter.""" 2 | 3 | import pytest 4 | 5 | 6 | class Tests: 7 | 8 | @pytest.mark.parametrize("param", ["param"]) 9 | def test_in_class_parameterized(self, param): 10 | """ 11 | This is my test inside `Tests` class with a parameter 12 | """ 13 | assert True 14 | -------------------------------------------------------------------------------- /examples/skip/test_simple_skip.py: -------------------------------------------------------------------------------- 1 | """Simple example skipped test.""" 2 | 3 | # Copyright (c) 2022 https://reportportal.io . 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License 15 | import pytest 16 | 17 | 18 | @pytest.mark.skip(reason="no way of currently testing this") 19 | def test_simple_skip(): 20 | assert False 21 | -------------------------------------------------------------------------------- /examples/skip/test_skip_issue.py: -------------------------------------------------------------------------------- 1 | """Simple example skipped test.""" 2 | 3 | # Copyright (c) 2022 https://reportportal.io . 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License 15 | import pytest 16 | 17 | ID = "ABC-1234" 18 | REASON = "some_bug" 19 | TYPE = "PB" 20 | 21 | 22 | @pytest.mark.issue(issue_id=ID, reason=REASON, issue_type=TYPE) 23 | @pytest.mark.skip(reason="no way of currently testing this") 24 | def test_simple_skip(): 25 | assert False 26 | -------------------------------------------------------------------------------- /examples/test_case_id/test_case_id_decorator.py: -------------------------------------------------------------------------------- 1 | """A simple example test with Test Case ID decorator.""" 2 | 3 | # Copyright (c) 2022 https://reportportal.io . 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License 15 | 16 | import pytest 17 | 18 | TEST_CASE_ID = "ISSUE-123" 19 | 20 | 21 | @pytest.mark.tc_id(TEST_CASE_ID) 22 | def test_case_id_decorator(): 23 | assert True 24 | -------------------------------------------------------------------------------- /examples/test_case_id/test_case_id_decorator_no_id.py: -------------------------------------------------------------------------------- 1 | """A simple example test with Test Case ID decorator no arguments.""" 2 | 3 | # Copyright (c) 2022 https://reportportal.io . 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License 15 | 16 | import pytest 17 | 18 | 19 | @pytest.mark.parametrize(("param1", "param2"), [("value1", "value2")]) 20 | @pytest.mark.tc_id 21 | def test_case_id_decorator(param1, param2): 22 | assert True 23 | -------------------------------------------------------------------------------- /examples/test_case_id/test_case_id_decorator_no_id_params_false.py: -------------------------------------------------------------------------------- 1 | """A simple example test with Test Case ID decorator no arguments.""" 2 | 3 | # Copyright (c) 2022 https://reportportal.io . 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License 15 | 16 | import pytest 17 | 18 | 19 | @pytest.mark.parametrize(("param1", "param2"), [("value1", "value2")]) 20 | @pytest.mark.tc_id(parameterized=False) 21 | def test_case_id_decorator(param1, param2): 22 | assert True 23 | -------------------------------------------------------------------------------- /examples/test_case_id/test_case_id_decorator_no_id_params_true.py: -------------------------------------------------------------------------------- 1 | """A simple example test with Test Case ID decorator no arguments.""" 2 | 3 | # Copyright (c) 2022 https://reportportal.io . 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License 15 | 16 | import pytest 17 | 18 | 19 | @pytest.mark.parametrize(("param1", "param2"), [("value1", "value2")]) 20 | @pytest.mark.tc_id(parameterized=True) 21 | def test_case_id_decorator(param1, param2): 22 | assert True 23 | -------------------------------------------------------------------------------- /examples/test_case_id/test_case_id_decorator_no_id_partial_params.py: -------------------------------------------------------------------------------- 1 | """A simple example test with Test Case ID decorator no arguments.""" 2 | 3 | # Copyright (c) 2022 https://reportportal.io . 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License 15 | 16 | import pytest 17 | 18 | 19 | @pytest.mark.parametrize(("param1", "param2"), [("value1", "value2")]) 20 | @pytest.mark.tc_id(params=["param2"]) 21 | def test_case_id_decorator(param1, param2): 22 | assert True 23 | -------------------------------------------------------------------------------- /examples/test_case_id/test_case_id_decorator_no_id_partial_params_true.py: -------------------------------------------------------------------------------- 1 | """A simple example test with Test Case ID decorator no arguments.""" 2 | 3 | # Copyright (c) 2022 https://reportportal.io . 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License 15 | 16 | import pytest 17 | 18 | 19 | @pytest.mark.parametrize(("param1", "param2"), [("value1", "value2")]) 20 | @pytest.mark.tc_id(parameterized=True, params=["param2"]) 21 | def test_case_id_decorator(param1, param2): 22 | assert True 23 | -------------------------------------------------------------------------------- /examples/test_case_id/test_case_id_decorator_params_false.py: -------------------------------------------------------------------------------- 1 | """A simple example test with Test Case ID decorator and parameters.""" 2 | 3 | # Copyright (c) 2022 https://reportportal.io . 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License 15 | 16 | import pytest 17 | 18 | TEST_CASE_ID = "ISSUE-321" 19 | 20 | 21 | @pytest.mark.parametrize(("param1", "param2"), [("value1", "value2")]) 22 | @pytest.mark.tc_id(TEST_CASE_ID, parameterized=False) 23 | def test_case_id_decorator(param1, param2): 24 | assert True 25 | -------------------------------------------------------------------------------- /examples/test_case_id/test_case_id_decorator_params_no.py: -------------------------------------------------------------------------------- 1 | """A simple example test with Test Case ID decorator and parameters.""" 2 | 3 | # Copyright (c) 2022 https://reportportal.io . 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License 15 | 16 | import pytest 17 | 18 | TEST_CASE_ID = "ISSUE-132" 19 | 20 | 21 | @pytest.mark.parametrize(("param1", "param2"), [("value1", "value2")]) 22 | @pytest.mark.tc_id(TEST_CASE_ID) 23 | def test_case_id_decorator(param1, param2): 24 | assert True 25 | -------------------------------------------------------------------------------- /examples/test_case_id/test_case_id_decorator_params_partially.py: -------------------------------------------------------------------------------- 1 | """A simple example test with Test Case ID decorator and parameters.""" 2 | 3 | # Copyright (c) 2022 https://reportportal.io . 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License 15 | 16 | import pytest 17 | 18 | TEST_CASE_ID = "ISSUE-213" 19 | 20 | 21 | @pytest.mark.parametrize(("param1", "param2"), [("value1", "value2")]) 22 | @pytest.mark.tc_id(TEST_CASE_ID, parameterized=True, params=["param1"]) 23 | def test_case_id_decorator(param1, param2): 24 | assert True 25 | -------------------------------------------------------------------------------- /examples/test_case_id/test_case_id_decorator_params_true.py: -------------------------------------------------------------------------------- 1 | """A simple example test with Test Case ID decorator and parameters.""" 2 | 3 | # Copyright (c) 2022 https://reportportal.io . 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License 15 | 16 | import pytest 17 | 18 | TEST_CASE_ID = "ISSUE-231" 19 | 20 | 21 | @pytest.mark.parametrize(("param1", "param2"), [("value1", "value2")]) 22 | @pytest.mark.tc_id(TEST_CASE_ID, parameterized=True) 23 | def test_case_id_decorator(param1, param2): 24 | assert True 25 | -------------------------------------------------------------------------------- /examples/test_issue_id.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 https://reportportal.io . 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | import pytest 15 | 16 | ID = "ABC-1234" 17 | REASON = "some_bug" 18 | TYPE = "PB" 19 | 20 | 21 | @pytest.mark.issue(issue_id=ID, reason=REASON, issue_type=TYPE) 22 | def test_issue_id(): 23 | assert False 24 | -------------------------------------------------------------------------------- /examples/test_issue_id_pass.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 https://reportportal.io . 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | import pytest 15 | 16 | ID = "ABC-1234" 17 | REASON = "some_bug" 18 | TYPE = "PB" 19 | 20 | 21 | @pytest.mark.issue(issue_id=ID, reason=REASON, issue_type=TYPE) 22 | def test_issue_id(): 23 | assert True 24 | -------------------------------------------------------------------------------- /examples/test_max_item_name.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | 16 | def test_thi_is_simple_example_test_with_the_name_longer_than_maximum_allowed_lorem_ipsum_dolor_sit_amet_consectetur_adipiscing_elit_sed_do_eiusmod_tempor_incididunt_ut_labore_et_dolore_magna_aliqua_ut_enim_ad_minim_veniam_quis_nostrud_exercitation_ullamco_laboris_nisi_ut_aliquip_ex_ea_commodo_consequat_duis_aute_irure_dolor_in_reprehenderit_in_voluptate_velit_esse_cillum_dolore_eu_fugiat_nulla_pariatur_excepteur_sint_occaecat_cupidatat_non_proident_sunt_in_culpa_qui_officia_deserunt_mollit_anim_id_est_laborum_sed_ut_perspiciatis_unde_omnis_iste_natus_error_sit_voluptatem_accusantium_doloremque_laudantium_totam_rem_aperiam_eaque_ipsa_quae_ab_illo_inventore_veritatis_et_quasi_architecto_beatae_vitae_dicta_sunt_explicabo_nemo_enim_ipsam_voluptatem_quia_voluptas_sit_aspernatur_aut_odit_aut_fugit_sed_quia_consequuntur_magni_dolores_eos_qui_ratione_voluptatem_sequi_nesciunt_neque_porro_quisquam_est_qui_dolorem_ipsum_quia_dolor_sit_amet_consectetur_adipisci_velit_sed_quia_non_numquam_eius_modi_tempora_incidunt_ut_labore_et_dolore_magnam_aliquam_quaerat_voluptatem(): # noqa: E501 17 | """Simple example test with the name longer than maximum allowed.""" 18 | assert True 19 | -------------------------------------------------------------------------------- /examples/test_rp_logging.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 https://reportportal.io . 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | import logging 15 | 16 | logging.basicConfig(level=logging.INFO) 17 | 18 | logger = logging.getLogger(__name__) 19 | 20 | LOG_MESSAGE = "Standard logger logs to Report Portal" 21 | 22 | 23 | def test_report_portal_logging(): 24 | logger.info(LOG_MESSAGE) 25 | -------------------------------------------------------------------------------- /examples/test_simple.py: -------------------------------------------------------------------------------- 1 | """Simple example test.""" 2 | 3 | # Copyright (c) 2022 https://reportportal.io . 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License 15 | 16 | 17 | def test_simple(): 18 | """Simple example test.""" 19 | assert True 20 | -------------------------------------------------------------------------------- /examples/test_simple_fail.py: -------------------------------------------------------------------------------- 1 | """Simple example test which fails.""" 2 | 3 | # Copyright (c) 2022 https://reportportal.io . 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # https://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License 15 | 16 | 17 | def test_simple_fail(): 18 | assert False 19 | -------------------------------------------------------------------------------- /examples/threads/test_thread_logging.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import threading 3 | 4 | from reportportal_client.steps import step 5 | 6 | log = logging.getLogger(__name__) 7 | 8 | 9 | def worker(): 10 | log.info("TEST_INFO") 11 | log.debug("TEST_DEBUG") 12 | 13 | 14 | def test_log(): 15 | t = threading.Thread(target=worker) 16 | log.info("TEST_BEFORE_THREADING") 17 | with step("Some nesting where the thread logs should go"): 18 | t.start() 19 | t.join() 20 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = [ 3 | # sync with setup.py until we discard non-pep-517/518 4 | "setuptools>=68.0.0", 5 | "setuptools-scm", 6 | "wheel==0.40.0", 7 | ] 8 | build-backend = "setuptools.build_meta" 9 | 10 | [tool.isort] 11 | py_version=310 12 | line_length = 119 13 | profile = "black" 14 | skip_gitignore = true 15 | 16 | [tool.black] 17 | line-length = 119 18 | target-version = ["py310"] 19 | -------------------------------------------------------------------------------- /pytest_reportportal/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 EPAM Systems 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | """This package contains Pytest agent's code for the Report Portal.""" 15 | 16 | __all__ = ["LAUNCH_WAIT_TIMEOUT"] 17 | 18 | LAUNCH_WAIT_TIMEOUT = 10 19 | -------------------------------------------------------------------------------- /pytest_reportportal/config.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 EPAM Systems 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | """This module contains class that stores RP agent configuration data.""" 15 | 16 | import warnings 17 | from os import getenv 18 | from typing import Any, List, Optional, Tuple, Union 19 | 20 | from _pytest.config import Config 21 | from reportportal_client import ClientType, OutputType 22 | from reportportal_client.helpers import to_bool 23 | from reportportal_client.logs import MAX_LOG_BATCH_PAYLOAD_SIZE 24 | 25 | try: 26 | # This try/except can go away once we support pytest >= 5.4.0 27 | from _pytest.logging import get_actual_log_level 28 | except ImportError: 29 | from _pytest.logging import get_log_level_for_setting as get_actual_log_level 30 | 31 | 32 | class AgentConfig: 33 | """Storage for the RP agent initialization attributes.""" 34 | 35 | rp_client_type: Optional[ClientType] 36 | rp_rerun: Optional[bool] 37 | pconfig: Config 38 | rp_endpoint: str 39 | rp_hierarchy_code: bool 40 | rp_dir_level: int 41 | rp_hierarchy_dirs: bool 42 | rp_hierarchy_test_file: bool 43 | rp_dir_path_separator: str 44 | rp_ignore_attributes: set 45 | rp_is_skipped_an_issue: bool 46 | rp_issue_id_marks: bool 47 | rp_bts_issue_url: str 48 | rp_bts_project: str 49 | rp_bts_url: str 50 | rp_launch: str 51 | rp_launch_id: Optional[str] 52 | rp_launch_attributes: Optional[List[str]] 53 | rp_tests_attributes: Optional[List[str]] 54 | rp_launch_description: str 55 | rp_log_batch_size: int 56 | rp_log_batch_payload_size: int 57 | rp_log_level: Optional[int] 58 | rp_log_format: Optional[str] 59 | rp_mode: str 60 | rp_parent_item_id: Optional[str] 61 | rp_project: str 62 | rp_rerun_of: Optional[str] 63 | rp_api_retries: int 64 | rp_skip_connection_test: bool 65 | rp_api_key: str 66 | rp_verify_ssl: Union[bool, str] 67 | rp_launch_timeout: int 68 | rp_launch_uuid_print: bool 69 | rp_launch_uuid_print_output: Optional[OutputType] 70 | rp_http_timeout: Optional[Union[Tuple[float, float], float]] 71 | rp_report_fixtures: bool 72 | 73 | def __init__(self, pytest_config: Config) -> None: 74 | """Initialize required attributes.""" 75 | self.rp_rerun = pytest_config.option.rp_rerun or pytest_config.getini("rp_rerun") 76 | self.rp_endpoint = self.find_option(pytest_config, "rp_endpoint") 77 | self.rp_hierarchy_code = to_bool(self.find_option(pytest_config, "rp_hierarchy_code")) 78 | self.rp_dir_level = int(self.find_option(pytest_config, "rp_hierarchy_dirs_level")) 79 | self.rp_hierarchy_dirs = to_bool(self.find_option(pytest_config, "rp_hierarchy_dirs")) 80 | self.rp_dir_path_separator = self.find_option(pytest_config, "rp_hierarchy_dir_path_separator") 81 | self.rp_hierarchy_test_file = to_bool(self.find_option(pytest_config, "rp_hierarchy_test_file")) 82 | self.rp_ignore_attributes = set(self.find_option(pytest_config, "rp_ignore_attributes") or []) 83 | self.rp_is_skipped_an_issue = self.find_option(pytest_config, "rp_is_skipped_an_issue") 84 | self.rp_issue_id_marks = self.find_option(pytest_config, "rp_issue_id_marks") 85 | self.rp_bts_issue_url = self.find_option(pytest_config, "rp_bts_issue_url") 86 | if not self.rp_bts_issue_url: 87 | self.rp_bts_issue_url = self.find_option(pytest_config, "rp_issue_system_url") 88 | if self.rp_bts_issue_url: 89 | warnings.warn( 90 | "Parameter `rp_issue_system_url` is deprecated since 5.4.0 and will be subject for removing" 91 | "in the next major version. Use `rp_bts_issue_url` argument instead.", 92 | DeprecationWarning, 93 | 2, 94 | ) 95 | self.rp_bts_project = self.find_option(pytest_config, "rp_bts_project") 96 | self.rp_bts_url = self.find_option(pytest_config, "rp_bts_url") 97 | self.rp_launch = self.find_option(pytest_config, "rp_launch") 98 | self.rp_launch_id = self.find_option(pytest_config, "rp_launch_id") 99 | self.rp_launch_attributes = self.find_option(pytest_config, "rp_launch_attributes") 100 | self.rp_tests_attributes = self.find_option(pytest_config, "rp_tests_attributes") 101 | self.rp_launch_description = self.find_option(pytest_config, "rp_launch_description") 102 | self.rp_log_batch_size = int(self.find_option(pytest_config, "rp_log_batch_size")) 103 | batch_payload_size = self.find_option(pytest_config, "rp_log_batch_payload_size") 104 | if batch_payload_size: 105 | self.rp_log_batch_payload_size = int(batch_payload_size) 106 | else: 107 | self.rp_log_batch_payload_size = MAX_LOG_BATCH_PAYLOAD_SIZE 108 | self.rp_log_level = get_actual_log_level(pytest_config, "rp_log_level") 109 | self.rp_log_format = self.find_option(pytest_config, "rp_log_format") 110 | self.rp_thread_logging = to_bool(self.find_option(pytest_config, "rp_thread_logging") or False) 111 | self.rp_mode = self.find_option(pytest_config, "rp_mode") 112 | self.rp_parent_item_id = self.find_option(pytest_config, "rp_parent_item_id") 113 | self.rp_project = self.find_option(pytest_config, "rp_project") 114 | self.rp_rerun_of = self.find_option(pytest_config, "rp_rerun_of") 115 | self.rp_skip_connection_test = to_bool(self.find_option(pytest_config, "rp_skip_connection_test")) 116 | 117 | rp_api_retries_str = self.find_option(pytest_config, "rp_api_retries") 118 | rp_api_retries = rp_api_retries_str and int(rp_api_retries_str) 119 | if rp_api_retries and rp_api_retries > 0: 120 | self.rp_api_retries = rp_api_retries 121 | else: 122 | rp_api_retries_str = self.find_option(pytest_config, "retries") 123 | rp_api_retries = rp_api_retries_str and int(rp_api_retries_str) 124 | if rp_api_retries and rp_api_retries > 0: 125 | self.rp_api_retries = rp_api_retries 126 | warnings.warn( 127 | "Parameter `retries` is deprecated since 5.1.9 " 128 | "and will be subject for removing in the next " 129 | "major version. Use `rp_api_retries` argument " 130 | "instead.", 131 | DeprecationWarning, 132 | 2, 133 | ) 134 | else: 135 | self.rp_api_retries = 0 136 | 137 | self.rp_api_key = getenv("RP_API_KEY") or self.find_option(pytest_config, "rp_api_key") 138 | if not self.rp_api_key: 139 | self.rp_api_key = getenv("RP_UUID") or self.find_option(pytest_config, "rp_uuid") 140 | if self.rp_api_key: 141 | warnings.warn( 142 | "Parameter `rp_uuid` is deprecated since 5.1.9 " 143 | "and will be subject for removing in the next " 144 | "major version. Use `rp_api_key` argument " 145 | "instead.", 146 | DeprecationWarning, 147 | 2, 148 | ) 149 | else: 150 | warnings.warn( 151 | "Argument `rp_api_key` is `None` or empty string, " 152 | "that is not supposed to happen because Report " 153 | "Portal is usually requires an authorization key. " 154 | "Please check your configuration.", 155 | RuntimeWarning, 156 | 2, 157 | ) 158 | 159 | rp_verify_ssl = self.find_option(pytest_config, "rp_verify_ssl", True) 160 | try: 161 | self.rp_verify_ssl = to_bool(rp_verify_ssl) 162 | except (ValueError, AttributeError): 163 | self.rp_verify_ssl = rp_verify_ssl 164 | self.rp_launch_timeout = int(self.find_option(pytest_config, "rp_launch_timeout")) 165 | 166 | self.rp_launch_uuid_print = to_bool(self.find_option(pytest_config, "rp_launch_uuid_print") or "False") 167 | print_output = self.find_option(pytest_config, "rp_launch_uuid_print_output") 168 | self.rp_launch_uuid_print_output = OutputType[print_output.upper()] if print_output else None 169 | client_type = self.find_option(pytest_config, "rp_client_type") 170 | self.rp_client_type = ClientType[client_type.upper()] if client_type else ClientType.SYNC 171 | 172 | connect_timeout = self.find_option(pytest_config, "rp_connect_timeout") 173 | connect_timeout = float(connect_timeout) if connect_timeout else None 174 | read_timeout = self.find_option(pytest_config, "rp_read_timeout") 175 | read_timeout = float(read_timeout) if read_timeout else None 176 | if connect_timeout is None and read_timeout is None: 177 | self.rp_http_timeout = None 178 | elif connect_timeout is not None and read_timeout is not None: 179 | self.rp_http_timeout = (connect_timeout, read_timeout) 180 | else: 181 | self.rp_http_timeout = connect_timeout or read_timeout 182 | self.rp_report_fixtures = to_bool(self.find_option(pytest_config, "rp_report_fixtures", False)) 183 | 184 | # noinspection PyMethodMayBeStatic 185 | def find_option(self, pytest_config: Config, option_name: str, default: Any = None) -> Any: 186 | """ 187 | Find a single configuration setting from multiple places. 188 | 189 | The value is retrieved in the following places in priority order: 190 | 191 | 1. From `self.pconfig.option.[option_name]`. 192 | 2. From `self.pconfig.getini(option_name)`. 193 | 194 | :param pytest_config: config object of PyTest 195 | :param option_name: name of the option 196 | :param default: value to be returned if not found 197 | :return: option value 198 | """ 199 | value = getattr(pytest_config.option, option_name, None) or pytest_config.getini(option_name) 200 | if isinstance(value, bool): 201 | return value 202 | return value or default 203 | -------------------------------------------------------------------------------- /pytest_reportportal/errors.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 EPAM Systems 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | """This module includes exceptions used in the package.""" 15 | 16 | 17 | class PytestWarning(UserWarning): 18 | """Pytest warning exception. 19 | 20 | This exception is about to stub absent PytestWarning in Pytest versions 21 | up to 3.8.0. Get rid of this code once we drop support for Pytest versions 22 | below 3.8.0. 23 | """ 24 | -------------------------------------------------------------------------------- /pytest_reportportal/rp_logging.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 https://reportportal.io . 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | """RPLogger class for low-level logging in tests.""" 15 | 16 | import logging 17 | import sys 18 | import threading 19 | from contextlib import contextmanager 20 | from functools import wraps 21 | from typing import Any, Dict, List 22 | 23 | from reportportal_client import RPLogger, current, set_current 24 | from reportportal_client.core.worker import APIWorker 25 | 26 | 27 | def is_api_worker(target): 28 | """Check if target is an RP worker thread.""" 29 | if target: 30 | method_name = getattr(target, "__name__", None) 31 | method_self = getattr(target, "__self__", None) 32 | if method_name == "_monitor" and method_self: 33 | clazz = getattr(method_self, "__class__", None) 34 | if clazz is APIWorker: 35 | return True 36 | return False 37 | 38 | 39 | @contextmanager 40 | def patching_thread_class(config): 41 | """ 42 | Add patch for Thread class. 43 | 44 | Set the parent thread client as the child thread's local client 45 | """ 46 | if not config.rp_thread_logging: 47 | # Do nothing 48 | yield 49 | else: 50 | original_start = threading.Thread.start 51 | original_run = threading.Thread.run 52 | try: 53 | 54 | def wrap_start(original_func): 55 | @wraps(original_func) 56 | def _start(self, *args, **kwargs): 57 | """Save the invoking thread's client if there is one.""" 58 | # Prevent an endless loop of workers being spawned 59 | target = getattr(self, "_target", None) 60 | if not is_api_worker(self) and not is_api_worker(target): 61 | current_client = current() 62 | self.parent_rp_client = current_client 63 | return original_func(self, *args, **kwargs) 64 | 65 | return _start 66 | 67 | def wrap_run(original_func): 68 | @wraps(original_func) 69 | def _run(self, *args, **kwargs): 70 | """Create a new client for the invoked thread.""" 71 | client = None 72 | if hasattr(self, "parent_rp_client") and self.parent_rp_client and not current(): 73 | parent = self.parent_rp_client 74 | client = parent.clone() 75 | try: 76 | return original_func(self, *args, **kwargs) 77 | finally: 78 | if client: 79 | # Stop the client and remove any references 80 | client.close() 81 | self.parent_rp_client = None 82 | del self.parent_rp_client 83 | set_current(None) 84 | 85 | return _run 86 | 87 | if not hasattr(threading.Thread, "patched"): 88 | # patch 89 | threading.Thread.patched = True 90 | threading.Thread.start = wrap_start(original_start) 91 | threading.Thread.run = wrap_run(original_run) 92 | yield 93 | 94 | finally: 95 | if hasattr(threading.Thread, "patched"): 96 | threading.Thread.start = original_start 97 | threading.Thread.run = original_run 98 | del threading.Thread.patched 99 | 100 | 101 | @contextmanager 102 | def patching_logger_class(): 103 | """ 104 | Add patch for RPLogger class. 105 | 106 | Updated attachment in logs 107 | :return: wrapped function 108 | """ 109 | logger_class = logging.getLoggerClass() 110 | original_log = logger_class._log 111 | original_makeRecord = logger_class.makeRecord 112 | 113 | try: 114 | 115 | def wrap_log(original_func): 116 | @wraps(original_func) 117 | def _log(self, *args: List[Any], **kwargs: Dict[str, Any]): 118 | my_kwargs = kwargs.copy() 119 | attachment = my_kwargs.pop("attachment", None) 120 | if attachment is not None: 121 | my_kwargs.setdefault("extra", {}).update({"attachment": attachment}) 122 | 123 | # Python 3.11 start catches stack frames in wrappers, 124 | # so add additional stack level skip to not show it 125 | if sys.version_info >= (3, 11): 126 | if "stacklevel" in my_kwargs: 127 | my_kwargs["stacklevel"] = my_kwargs["stacklevel"] + 1 128 | else: 129 | my_kwargs["stacklevel"] = 2 130 | return original_func(self, *args, **my_kwargs) 131 | else: 132 | return original_func(self, *args, **my_kwargs) 133 | 134 | return _log 135 | 136 | def wrap_makeRecord(original_func): 137 | @wraps(original_func) 138 | def makeRecord(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None, sinfo=None): 139 | if extra is not None: 140 | attachment = extra.pop("attachment", None) 141 | else: 142 | attachment = None 143 | try: 144 | # Python 3.5 145 | record = original_func( 146 | self, name, level, fn, lno, msg, args, exc_info, func=func, extra=extra, sinfo=sinfo 147 | ) 148 | except TypeError: 149 | # Python 2.7 150 | record = original_func(self, name, level, fn, lno, msg, args, exc_info, func=func, extra=extra) 151 | record.attachment = attachment 152 | return record 153 | 154 | return makeRecord 155 | 156 | if not issubclass(logger_class, RPLogger): 157 | logger_class._log = wrap_log(logger_class._log) 158 | logger_class.makeRecord = wrap_makeRecord(logger_class.makeRecord) 159 | logging.setLoggerClass(RPLogger) 160 | yield 161 | 162 | finally: 163 | if not issubclass(logger_class, RPLogger): 164 | logger_class._log = original_log 165 | logger_class.makeRecord = original_makeRecord 166 | logging.setLoggerClass(logger_class) 167 | -------------------------------------------------------------------------------- /requirements-dev-bdd.txt: -------------------------------------------------------------------------------- 1 | pytest-bdd>=7.2.0 2 | -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | delayed-assert 2 | pytest-cov 3 | pytest-parallel 4 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | dill>=0.3.6 2 | pytest>=4.6.10 3 | reportportal-client~=5.6.4 4 | aenum>=3.1.0 5 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [aliases] 2 | test=pytest 3 | 4 | [metadata] 5 | description_file = README.rst 6 | 7 | [sdist] 8 | formats=gztar 9 | 10 | [bdist_wheel] 11 | universal = 1 12 | 13 | [tool:pytest] 14 | addopts=-vv 15 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 EPAM Systems 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | """Config for setup package pytest agent.""" 15 | 16 | import os 17 | 18 | from setuptools import setup 19 | 20 | __version__ = "5.5.1" 21 | 22 | 23 | def read_file(fname): 24 | """Read the given file. 25 | 26 | :param fname: Filename to be read 27 | :return: File content 28 | """ 29 | with open(os.path.join(os.path.dirname(__file__), fname)) as f: 30 | return f.read() 31 | 32 | 33 | setup( 34 | name="pytest-reportportal", 35 | version=__version__, 36 | description="Agent for Reporting results of tests to the Report Portal", 37 | long_description=read_file("README.md"), 38 | long_description_content_type="text/markdown", 39 | author="Report Portal Team", 40 | author_email="support@reportportal.io", 41 | url="https://github.com/reportportal/agent-python-pytest", 42 | packages=["pytest_reportportal"], 43 | package_data={"pytest_reportportal": ["*.pyi"]}, 44 | install_requires=read_file("requirements.txt").splitlines(), 45 | license="Apache 2.0", 46 | keywords=["testing", "reporting", "reportportal", "pytest", "agent"], 47 | classifiers=[ 48 | "Framework :: Pytest", 49 | "Programming Language :: Python :: 3.8", 50 | "Programming Language :: Python :: 3.9", 51 | "Programming Language :: Python :: 3.10", 52 | "Programming Language :: Python :: 3.11", 53 | "Programming Language :: Python :: 3.12", 54 | "Programming Language :: Python :: 3.13", 55 | ], 56 | entry_points={ 57 | "pytest11": [ 58 | "pytest_reportportal = pytest_reportportal.plugin", 59 | ] 60 | }, 61 | ) 62 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 https://reportportal.io . 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | """This package contains tests for the project.""" 15 | 16 | REPORT_PORTAL_SERVICE = "reportportal_client.RPClient" 17 | REQUESTS_SERVICE = "reportportal_client.client.requests.Session" 18 | -------------------------------------------------------------------------------- /tests/helpers/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 https://reportportal.io . 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | """This package contains integration tests for the project.""" 15 | -------------------------------------------------------------------------------- /tests/helpers/utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 https://reportportal.io . 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | """This module contains utility code for unit tests.""" 15 | 16 | import os 17 | import random 18 | import time 19 | from multiprocessing.pool import ThreadPool 20 | 21 | import pytest 22 | 23 | DEFAULT_VARIABLES = { 24 | "rp_launch": "Pytest", 25 | "rp_endpoint": "http://localhost:8080", 26 | "rp_project": "default_personal", 27 | "rp_api_key": "test_api_key", 28 | "rp_skip_connection_test": "True", 29 | } 30 | 31 | DEFAULT_PROJECT_SETTINGS = { 32 | "project": 2, 33 | "subTypes": { 34 | "NO_DEFECT": [ 35 | { 36 | "id": 4, 37 | "locator": "nd001", 38 | "typeRef": "NO_DEFECT", 39 | "longName": "No Defect", 40 | "shortName": "ND", 41 | "color": "#777777", 42 | } 43 | ], 44 | "TO_INVESTIGATE": [ 45 | { 46 | "id": 1, 47 | "locator": "ti001", 48 | "typeRef": "TO_INVESTIGATE", 49 | "longName": "To Investigate", 50 | "shortName": "TI", 51 | "color": "#ffb743", 52 | } 53 | ], 54 | "AUTOMATION_BUG": [ 55 | { 56 | "id": 2, 57 | "locator": "ab001", 58 | "typeRef": "AUTOMATION_BUG", 59 | "longName": "Automation Bug", 60 | "shortName": "AB", 61 | "color": "#f7d63e", 62 | } 63 | ], 64 | "PRODUCT_BUG": [ 65 | { 66 | "id": 3, 67 | "locator": "pb001", 68 | "typeRef": "PRODUCT_BUG", 69 | "longName": "Product Bug", 70 | "shortName": "PB", 71 | "color": "#ec3900", 72 | } 73 | ], 74 | "SYSTEM_ISSUE": [ 75 | { 76 | "id": 5, 77 | "locator": "si001", 78 | "typeRef": "SYSTEM_ISSUE", 79 | "longName": "System Issue", 80 | "shortName": "SI", 81 | "color": "#0274d1", 82 | } 83 | ], 84 | }, 85 | } 86 | 87 | 88 | def run_pytest_tests(tests, args=None, variables=None): 89 | """Run specific pytest tests. 90 | 91 | :param tests: a list of tests to run 92 | :param args: command line arguments which will be passed to pytest 93 | :param variables: parameter variables which will be passed to pytest 94 | :return: exit code 95 | """ 96 | if args is None: 97 | args = [] 98 | if variables is None: 99 | variables = DEFAULT_VARIABLES 100 | 101 | arguments = ["--reportportal"] + args 102 | for k, v in variables.items(): 103 | arguments.append("-o") 104 | arguments.append("{0}={1}".format(k, str(v))) 105 | 106 | if tests is not None: 107 | for t in tests: 108 | arguments.append(t) 109 | 110 | # Workaround collisions with parent test 111 | current_test = os.environ["PYTEST_CURRENT_TEST"] 112 | del os.environ["PYTEST_CURRENT_TEST"] 113 | result = pytest.main(arguments) 114 | os.environ["PYTEST_CURRENT_TEST"] = current_test 115 | 116 | return result 117 | 118 | 119 | def item_id_gen(**kwargs): 120 | return "{}-{}-{}".format(kwargs["name"], str(round(time.time() * 1000)), random.randint(0, 9999)) 121 | 122 | 123 | def project_settings(**_): 124 | return DEFAULT_PROJECT_SETTINGS 125 | 126 | 127 | def attributes_to_tuples(attributes): 128 | result = set() 129 | for attribute in attributes: 130 | if "key" in attribute: 131 | result.add((attribute["key"], attribute["value"])) 132 | else: 133 | result.add((None, attribute["value"])) 134 | return result 135 | 136 | 137 | # noinspection PyProtectedMember 138 | def run_tests_with_client(client, tests, args=None, variables=None): 139 | def test_func(): 140 | from reportportal_client import set_current 141 | 142 | set_current(client) 143 | return run_pytest_tests(tests, args, variables) 144 | 145 | pool = ThreadPool(processes=1) 146 | async_result = pool.apply_async(test_func) 147 | result = async_result.get() 148 | pool.terminate() 149 | return result 150 | -------------------------------------------------------------------------------- /tests/integration/test_attributes.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 https://reportportal.io . 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | """This module includes integration tests for different attribute reporting.""" 15 | 16 | from unittest import mock 17 | 18 | import pytest 19 | 20 | from tests import REPORT_PORTAL_SERVICE 21 | from tests.helpers import utils 22 | 23 | 24 | @mock.patch(REPORT_PORTAL_SERVICE) 25 | def test_custom_attribute_report(mock_client_init): 26 | """Verify custom attribute is reported. 27 | 28 | :param mock_client_init: Pytest fixture 29 | """ 30 | variables = {"markers": "scope: to which test scope a test relates"} 31 | variables.update(utils.DEFAULT_VARIABLES.items()) 32 | result = utils.run_pytest_tests(tests=["examples/attributes/test_one_attribute.py"], variables=variables) 33 | assert int(result) == 0, "Exit code should be 0 (no errors)" 34 | 35 | mock_client = mock_client_init.return_value 36 | assert mock_client.start_test_item.call_count > 0, '"start_test_item" called incorrect number of times' 37 | 38 | call_args = mock_client.start_test_item.call_args_list 39 | step_call_args = call_args[-1][1] 40 | assert step_call_args["attributes"] == [{"key": "scope", "value": "smoke"}] 41 | 42 | 43 | @mock.patch(REPORT_PORTAL_SERVICE) 44 | def test_custom_attribute_not_reported_if_skip_configured(mock_client_init): 45 | """Verify custom attribute is not reported if it's configured as skipped. 46 | 47 | :param mock_client_init: Pytest fixture 48 | """ 49 | variables = {"markers": "scope: to which test scope a test relates", "rp_ignore_attributes": "scope"} 50 | variables.update(utils.DEFAULT_VARIABLES.items()) 51 | result = utils.run_pytest_tests(tests=["examples/attributes/test_one_attribute.py"], variables=variables) 52 | assert int(result) == 0, "Exit code should be 0 (no errors)" 53 | 54 | mock_client = mock_client_init.return_value 55 | assert mock_client.start_test_item.call_count > 0, '"start_test_item" called incorrect number of times' 56 | 57 | call_args = mock_client.start_test_item.call_args_list 58 | step_call_args = call_args[-1][1] 59 | assert step_call_args["attributes"] == [] 60 | 61 | 62 | @mock.patch(REPORT_PORTAL_SERVICE) 63 | def test_two_attributes_different_values_report(mock_client_init): 64 | """Verify two attributes with different values is reported. 65 | 66 | :param mock_client_init: Pytest fixture 67 | """ 68 | variables = {"markers": "scope: to which test scope a test relates"} 69 | variables.update(utils.DEFAULT_VARIABLES.items()) 70 | result = utils.run_pytest_tests( 71 | tests=["examples/attributes/test_two_attributes_with_same_key.py"], variables=variables 72 | ) 73 | assert int(result) == 0, "Exit code should be 0 (no errors)" 74 | 75 | mock_client = mock_client_init.return_value 76 | assert mock_client.start_test_item.call_count > 0, '"start_test_item" called incorrect number of times' 77 | 78 | call_args = mock_client.start_test_item.call_args_list 79 | step_call_args = call_args[-1][1] 80 | actual_attributes = step_call_args["attributes"] 81 | 82 | assert utils.attributes_to_tuples(actual_attributes) == {("scope", "smoke"), ("scope", "regression")} 83 | 84 | 85 | @mock.patch(REPORT_PORTAL_SERVICE) 86 | def test_skip_attribute(mock_client_init): 87 | """Skip attribute is reported as tag. 88 | 89 | :param mock_client_init: Pytest fixture 90 | """ 91 | result = utils.run_pytest_tests(tests=["examples/skip/test_simple_skip.py"]) 92 | assert int(result) == 0, "Exit code should be 0 (no errors)" 93 | 94 | mock_client = mock_client_init.return_value 95 | assert mock_client.start_test_item.call_count > 0, '"start_test_item" called incorrect number of times' 96 | 97 | call_args = mock_client.start_test_item.call_args_list 98 | step_call_args = call_args[-1][1] 99 | actual_attributes = step_call_args["attributes"] 100 | 101 | assert utils.attributes_to_tuples(actual_attributes) == {(None, "skip")} 102 | 103 | 104 | @mock.patch(REPORT_PORTAL_SERVICE) 105 | def test_custom_runtime_attribute_report(mock_client_init): 106 | """Verify custom attribute is reported. 107 | 108 | :param mock_client_init: Pytest fixture 109 | """ 110 | variables = {"markers": "scope: to which test scope a test relates\nruntime: runtime attribute mark"} 111 | variables.update(utils.DEFAULT_VARIABLES.items()) 112 | result = utils.run_pytest_tests(tests=["examples/attributes/test_runtime_attribute.py"], variables=variables) 113 | assert int(result) == 0, "Exit code should be 0 (no errors)" 114 | 115 | mock_client = mock_client_init.return_value 116 | assert mock_client.start_test_item.call_count > 0, '"start_test_item" called incorrect number of times' 117 | assert mock_client.finish_test_item.call_count > 0, '"finish_test_item" called incorrect number of times' 118 | 119 | start_call_args = mock_client.start_test_item.call_args_list 120 | start_step_call_args = start_call_args[-1][1] 121 | assert start_step_call_args["attributes"] == [{"key": "scope", "value": "smoke"}] 122 | 123 | finish_call_args = mock_client.finish_test_item.call_args_list 124 | finish_step_call_args = finish_call_args[-1][1] 125 | actual_attributes = finish_step_call_args["attributes"] 126 | attribute_tuple_list = [(kv.get("key"), kv["value"]) for kv in actual_attributes] 127 | 128 | assert set(attribute_tuple_list) == {("scope", "smoke"), (None, "runtime")} 129 | 130 | 131 | @pytest.mark.parametrize("rp_hierarchy_code", [True, False]) 132 | @mock.patch(REPORT_PORTAL_SERVICE) 133 | def test_rp_tests_attributes(mock_client_init, rp_hierarchy_code): 134 | """Verify configuration attributes are reported. 135 | 136 | :param mock_client_init: Pytest fixture 137 | """ 138 | variables = {"rp_tests_attributes": "test_key:test_value", "rp_hierarchy_code": rp_hierarchy_code} 139 | variables.update(utils.DEFAULT_VARIABLES.items()) 140 | result = utils.run_pytest_tests(tests=["examples/test_simple.py"], variables=variables) 141 | assert int(result) == 0, "Exit code should be 0 (no errors)" 142 | 143 | mock_client = mock_client_init.return_value 144 | assert mock_client.start_test_item.call_count > 0, '"start_test_item" called incorrect number of times' 145 | 146 | call_args = mock_client.start_test_item.call_args_list 147 | step_call_args = call_args[-1][1] 148 | assert step_call_args["attributes"] == [{"key": "test_key", "value": "test_value"}] 149 | 150 | 151 | @mock.patch(REPORT_PORTAL_SERVICE) 152 | def test_rp_tests_attributes_add(mock_client_init): 153 | """Verify configuration attributes are reported along with custom attribute. 154 | 155 | :param mock_client_init: Pytest fixture 156 | """ 157 | variables = {"markers": "scope: to which test scope a test relates", "rp_tests_attributes": "test_key:test_value"} 158 | variables.update(utils.DEFAULT_VARIABLES.items()) 159 | result = utils.run_pytest_tests(tests=["examples/attributes/test_one_attribute.py"], variables=variables) 160 | assert int(result) == 0, "Exit code should be 0 (no errors)" 161 | 162 | mock_client = mock_client_init.return_value 163 | assert mock_client.start_test_item.call_count > 0, '"start_test_item" called incorrect number of times' 164 | 165 | call_args = mock_client.start_test_item.call_args_list 166 | step_call_args = call_args[-1][1] 167 | attributes = step_call_args["attributes"] 168 | assert len(attributes) == 2 169 | assert {"key": "scope", "value": "smoke"} in attributes 170 | assert {"key": "test_key", "value": "test_value"} in attributes 171 | -------------------------------------------------------------------------------- /tests/integration/test_case_id_report.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 https://reportportal.io . 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | """This module includes integration tests for Test Case ID report.""" 15 | 16 | from unittest import mock 17 | 18 | import pytest 19 | 20 | from examples.test_case_id import ( 21 | test_case_id_decorator, 22 | test_case_id_decorator_params_false, 23 | test_case_id_decorator_params_no, 24 | test_case_id_decorator_params_partially, 25 | test_case_id_decorator_params_true, 26 | ) 27 | from tests import REPORT_PORTAL_SERVICE 28 | from tests.helpers import utils 29 | 30 | 31 | @mock.patch(REPORT_PORTAL_SERVICE) 32 | @pytest.mark.parametrize( 33 | ["test", "expected_id"], 34 | [ 35 | ("examples/test_simple.py", "examples/test_simple.py:test_simple"), 36 | ( 37 | "examples/params/test_in_class_parameterized.py", 38 | "examples/params/test_in_class_parameterized.py:Tests.test_in_class_parameterized[param]", 39 | ), 40 | ("examples/test_case_id/test_case_id_decorator.py", test_case_id_decorator.TEST_CASE_ID), 41 | ( 42 | "examples/test_case_id/test_case_id_decorator_params_false.py", 43 | test_case_id_decorator_params_false.TEST_CASE_ID, 44 | ), 45 | ("examples/test_case_id/test_case_id_decorator_params_no.py", test_case_id_decorator_params_no.TEST_CASE_ID), 46 | ( 47 | "examples/test_case_id/test_case_id_decorator_params_partially.py", 48 | test_case_id_decorator_params_partially.TEST_CASE_ID + "[value1]", 49 | ), 50 | ( 51 | "examples/test_case_id/test_case_id_decorator_params_true.py", 52 | test_case_id_decorator_params_true.TEST_CASE_ID + "[value1,value2]", 53 | ), 54 | ("examples/test_case_id/test_case_id_decorator_no_id.py", ""), 55 | ("examples/test_case_id/test_case_id_decorator_no_id_params_false.py", ""), 56 | ("examples/test_case_id/test_case_id_decorator_no_id_params_true.py", "[value1,value2]"), 57 | ("examples/test_case_id/test_case_id_decorator_no_id_partial_params_true.py", "[value2]"), 58 | ], 59 | ) 60 | def test_parameters(mock_client_init, test, expected_id): 61 | """Verify different tests have correct Test Case IDs. 62 | 63 | :param mock_client_init: Pytest fixture 64 | :param test: a test to run 65 | :param expected_id: an expected Test Case ID 66 | """ 67 | result = utils.run_pytest_tests(tests=[test]) 68 | assert int(result) == 0, "Exit code should be 0 (no errors)" 69 | 70 | mock_client = mock_client_init.return_value 71 | assert mock_client.start_test_item.call_count > 0, '"start_test_item" called incorrect number of times' 72 | 73 | call_args = mock_client.start_test_item.call_args_list 74 | step_call_args = call_args[-1][1] 75 | assert step_call_args["test_case_id"] == expected_id 76 | -------------------------------------------------------------------------------- /tests/integration/test_code_reference.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 https://reportportal.io . 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | """This module includes integration tests for code references generation.""" 15 | 16 | from unittest import mock 17 | 18 | import pytest 19 | 20 | from tests import REPORT_PORTAL_SERVICE 21 | from tests.helpers import utils 22 | 23 | 24 | @mock.patch(REPORT_PORTAL_SERVICE) 25 | @pytest.mark.parametrize( 26 | ["test", "code_ref"], 27 | [ 28 | ("examples/test_simple.py", "examples/test_simple.py:test_simple"), 29 | ( 30 | "examples/params/test_in_class_parameterized.py", 31 | "examples/params/test_in_class_parameterized.py:Tests.test_in_class_parameterized", 32 | ), 33 | ("examples/hierarchy/test_in_class.py", "examples/hierarchy/test_in_class.py:Tests.test_in_class"), 34 | ( 35 | "examples/hierarchy/test_in_class_in_class.py", 36 | "examples/hierarchy/test_in_class_in_class.py:Tests.Test.test_in_class_in_class", 37 | ), 38 | ], 39 | ) 40 | def test_code_reference(mock_client_init, test, code_ref): 41 | """Verify different tests have correct code reference. 42 | 43 | :param mock_client_init: Pytest fixture 44 | :param test: a test to run 45 | :param code_ref: an expected code reference value 46 | """ 47 | result = utils.run_pytest_tests(tests=[test]) 48 | assert int(result) == 0, "Exit code should be 0 (no errors)" 49 | 50 | mock_client = mock_client_init.return_value 51 | assert mock_client.start_test_item.call_count > 0, '"start_test_item" called incorrect number of times' 52 | 53 | call_args = mock_client.start_test_item.call_args_list 54 | step_call_args = call_args[-1][1] 55 | assert step_call_args["code_ref"] == code_ref 56 | -------------------------------------------------------------------------------- /tests/integration/test_connection_close.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 https://reportportal.io . 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | from unittest import mock 15 | 16 | from tests import REPORT_PORTAL_SERVICE 17 | from tests.helpers import utils 18 | 19 | 20 | @mock.patch(REPORT_PORTAL_SERVICE) 21 | def test_connection_close(mock_client_init): 22 | mock_client = mock_client_init.return_value 23 | 24 | result = utils.run_tests_with_client(mock_client, ["examples/test_rp_logging.py"]) 25 | 26 | assert int(result) == 0, "Exit code should be 0 (no errors)" 27 | assert mock_client.close.call_count == 1, '"close" method was not called at the end of the test' 28 | -------------------------------------------------------------------------------- /tests/integration/test_custom_name.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from unittest import mock 16 | 17 | import pytest 18 | 19 | from examples.custom_name.test_custom_name_args import TEST_NAME_ARGS 20 | from examples.custom_name.test_custom_name_empty import TEST_NAME_EMPTY 21 | from examples.custom_name.test_custom_name_kwargs import TEST_NAME_KWARGS 22 | from tests import REPORT_PORTAL_SERVICE 23 | from tests.helpers import utils 24 | 25 | 26 | @pytest.mark.parametrize( 27 | "test, expected", 28 | [ 29 | ("examples/custom_name/test_custom_name_args.py", TEST_NAME_ARGS), 30 | ("examples/custom_name/test_custom_name_kwargs.py", TEST_NAME_KWARGS), 31 | ("examples/custom_name/test_custom_name_empty.py", TEST_NAME_EMPTY), 32 | ], 33 | ) 34 | @mock.patch(REPORT_PORTAL_SERVICE) 35 | def test_custom_attribute_report(mock_client_init, test, expected): 36 | result = utils.run_pytest_tests(tests=[test], variables=utils.DEFAULT_VARIABLES) 37 | assert int(result) == 0, "Exit code should be 0 (no errors)" 38 | 39 | mock_client = mock_client_init.return_value 40 | start_count = mock_client.start_test_item.call_count 41 | finish_count = mock_client.finish_test_item.call_count 42 | assert start_count == finish_count == 1, 'Incorrect number of "start_test_item" or "finish_test_item" calls' 43 | 44 | call_args = mock_client.start_test_item.call_args_list 45 | step_call_args = call_args[0][1] 46 | assert step_call_args["name"] == expected, "Incorrect item name" 47 | assert step_call_args["attributes"] == [], "No attributes should be added for the test item" 48 | -------------------------------------------------------------------------------- /tests/integration/test_debug_mode.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 https://reportportal.io . 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | """This module includes integration tests for the debug mode switch.""" 15 | 16 | from unittest import mock 17 | 18 | import pytest 19 | 20 | from tests import REPORT_PORTAL_SERVICE 21 | from tests.helpers import utils 22 | 23 | 24 | @mock.patch(REPORT_PORTAL_SERVICE) 25 | @pytest.mark.parametrize(["mode", "expected_mode"], [("DEFAULT", "DEFAULT"), ("DEBUG", "DEBUG"), (None, "DEFAULT")]) 26 | def test_launch_mode(mock_client_init, mode, expected_mode): 27 | """Verify different launch modes are passed to `start_launch` method. 28 | 29 | :param mock_client_init: Pytest fixture 30 | :param mode: a variable to be passed to pytest 31 | :param expected_mode: a value which should be passed to 32 | ReportPortalService 33 | """ 34 | variables = dict() 35 | if mode is not None: 36 | variables["rp_mode"] = mode 37 | variables.update(utils.DEFAULT_VARIABLES.items()) 38 | result = utils.run_pytest_tests(tests=["examples/test_simple.py"], variables=variables) 39 | assert int(result) == 0, "Exit code should be 0 (no errors)" 40 | 41 | assert mock_client_init.call_count == 1, "client wasn't initialized" 42 | 43 | init_kwargs = mock_client_init.call_args_list[0][1] 44 | assert "mode" in init_kwargs 45 | assert init_kwargs["mode"] == expected_mode 46 | -------------------------------------------------------------------------------- /tests/integration/test_empty_run.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 https://reportportal.io . 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | """This module includes integration tests for the empty run.""" 15 | 16 | from unittest import mock 17 | 18 | from tests import REPORT_PORTAL_SERVICE 19 | from tests.helpers import utils 20 | 21 | 22 | @mock.patch(REPORT_PORTAL_SERVICE) 23 | def test_empty_run(mock_client_init): 24 | """Verify that RP plugin does not fail if there is not tests in run. 25 | 26 | :param mock_client_init: Pytest fixture 27 | """ 28 | result = utils.run_pytest_tests(tests=["examples/empty/"]) 29 | 30 | assert int(result) == 5, "Exit code should be 5 (no tests)" 31 | 32 | mock_client = mock_client_init.return_value 33 | assert mock_client.start_launch.call_count == 1, '"start_launch" method was not called' 34 | assert mock_client.finish_launch.call_count == 1, '"finish_launch" method was not called' 35 | 36 | finish_args = mock_client.finish_launch.call_args_list 37 | assert "status" not in finish_args[0][1], "Launch status should not be defined" 38 | launch_end_time = finish_args[0][1]["end_time"] 39 | assert launch_end_time is not None and int(launch_end_time) > 0, "Launch end time is empty" 40 | -------------------------------------------------------------------------------- /tests/integration/test_issue_report.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 https://reportportal.io . 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | """This module includes integration test for issue type reporting.""" 15 | 16 | from unittest import mock 17 | 18 | import pytest 19 | from delayed_assert import assert_expectations, expect 20 | from reportportal_client.core.rp_issues import Issue 21 | 22 | from examples import test_issue_id 23 | from pytest_reportportal.service import NOT_ISSUE 24 | from tests import REPORT_PORTAL_SERVICE 25 | from tests.helpers import utils 26 | 27 | ISSUE_PLACEHOLDER = "{issue_id}" 28 | ISSUE_URL_PATTERN = f"https://bugzilla.some.com/show_bug.cgi?id={ISSUE_PLACEHOLDER}" 29 | BTS_PROJECT = "RP-TEST" 30 | BTS_URL = "https://bugzilla.some.com" 31 | 32 | 33 | @mock.patch(REPORT_PORTAL_SERVICE) 34 | @pytest.mark.parametrize("issue_id_mark", [True, False]) 35 | def test_issue_id_attribute(mock_client_init, issue_id_mark): 36 | """Verify agent reports issue attribute if configured. 37 | 38 | :param mock_client_init: Pytest fixture 39 | :param issue_id_mark: Attribute report configuration 40 | """ 41 | mock_client = mock_client_init.return_value 42 | mock_client.start_test_item.side_effect = utils.item_id_gen 43 | mock_client.get_project_settings.side_effect = utils.project_settings 44 | 45 | variables = {"rp_issue_id_marks": issue_id_mark} 46 | variables.update(utils.DEFAULT_VARIABLES.items()) 47 | result = utils.run_pytest_tests(tests=["examples/test_issue_id.py"], variables=variables) 48 | assert int(result) == 1, "Exit code should be 1 (test failed)" 49 | 50 | call_args = mock_client.start_test_item.call_args_list 51 | finish_test_step = call_args[-1][1] 52 | attributes = finish_test_step["attributes"] 53 | 54 | if issue_id_mark: 55 | assert len(attributes) == 1 56 | issue_attribute = attributes[0] 57 | expect(issue_attribute["key"] == "issue") 58 | expect(issue_attribute["value"] == test_issue_id.ID) 59 | assert_expectations() 60 | else: 61 | assert len(attributes) == 0 62 | 63 | 64 | @mock.patch(REPORT_PORTAL_SERVICE) 65 | def test_issue_report(mock_client_init): 66 | """Verify agent reports issue ids and defect type. 67 | 68 | :param mock_client_init: Pytest fixture 69 | """ 70 | mock_client = mock_client_init.return_value 71 | mock_client.start_test_item.side_effect = utils.item_id_gen 72 | mock_client.get_project_settings.side_effect = utils.project_settings 73 | 74 | variables = {"rp_issue_system_url": ISSUE_URL_PATTERN} 75 | variables.update(utils.DEFAULT_VARIABLES.items()) 76 | result = utils.run_pytest_tests(tests=["examples/test_issue_id.py"], variables=variables) 77 | assert int(result) == 1, "Exit code should be 1 (test failed)" 78 | 79 | call_args = mock_client.finish_test_item.call_args_list 80 | finish_test_step = call_args[0][1] 81 | issue = finish_test_step["issue"] 82 | 83 | assert isinstance(issue, Issue) 84 | expect(issue.issue_type == "pb001") 85 | expect(issue.comment is not None) 86 | assert_expectations() 87 | comments = issue.comment.split("\n") 88 | assert len(comments) == 1 89 | comment = comments[0] 90 | assert comment == "* {}: [{}]({})".format( 91 | test_issue_id.REASON, test_issue_id.ID, ISSUE_URL_PATTERN.replace(ISSUE_PLACEHOLDER, test_issue_id.ID) 92 | ) 93 | 94 | 95 | @mock.patch(REPORT_PORTAL_SERVICE) 96 | def test_passed_no_issue_report(mock_client_init): 97 | """Verify agent do not report issue if test passed. 98 | 99 | :param mock_client_init: Pytest fixture 100 | """ 101 | mock_client = mock_client_init.return_value 102 | mock_client.start_test_item.side_effect = utils.item_id_gen 103 | mock_client.get_project_settings.side_effect = utils.project_settings 104 | 105 | variables = {"rp_issue_system_url": ISSUE_URL_PATTERN} 106 | variables.update(utils.DEFAULT_VARIABLES.items()) 107 | result = utils.run_pytest_tests(tests=["examples/test_issue_id_pass.py"], variables=variables) 108 | assert int(result) == 0, "Exit code should be 0 (no failures)" 109 | 110 | call_args = mock_client.finish_test_item.call_args_list 111 | finish_test_step = call_args[0][1] 112 | assert "issue" not in finish_test_step or finish_test_step["issue"] is None 113 | 114 | 115 | @pytest.mark.parametrize(("flag_value", "expected_issue"), [(True, None), (False, NOT_ISSUE), (None, None)]) 116 | @mock.patch(REPORT_PORTAL_SERVICE) 117 | def test_skipped_not_issue(mock_client_init, flag_value, expected_issue): 118 | """Verify 'rp_is_skipped_an_issue' option handling. 119 | 120 | :param mock_client_init: mocked Report Portal client Pytest fixture 121 | :param flag_value: option value to set during the test 122 | :param expected_issue: result issue value to verify 123 | """ 124 | mock_client = mock_client_init.return_value 125 | mock_client.start_test_item.side_effect = utils.item_id_gen 126 | 127 | variables = dict() 128 | if flag_value is not None: 129 | variables["rp_is_skipped_an_issue"] = flag_value 130 | variables.update(utils.DEFAULT_VARIABLES.items()) 131 | 132 | result = utils.run_pytest_tests(tests=["examples/skip/test_simple_skip.py"], variables=variables) 133 | 134 | assert int(result) == 0, "Exit code should be 0 (no failures)" 135 | call_args = mock_client.finish_test_item.call_args_list 136 | finish_test_step = call_args[0][1] 137 | actual_issue = finish_test_step.get("issue", None) 138 | assert actual_issue == expected_issue 139 | 140 | 141 | @mock.patch(REPORT_PORTAL_SERVICE) 142 | def test_skipped_custom_issue(mock_client_init): 143 | """Verify skipped test with issue decorator handling. 144 | 145 | :param mock_client_init: mocked Report Portal client Pytest fixture 146 | """ 147 | mock_client = mock_client_init.return_value 148 | mock_client.start_test_item.side_effect = utils.item_id_gen 149 | mock_client.get_project_settings.side_effect = utils.project_settings 150 | 151 | variables = dict() 152 | variables["rp_is_skipped_an_issue"] = True 153 | variables["rp_issue_system_url"] = ISSUE_URL_PATTERN 154 | variables.update(utils.DEFAULT_VARIABLES.items()) 155 | 156 | result = utils.run_pytest_tests(tests=["examples/skip/test_skip_issue.py"], variables=variables) 157 | 158 | assert int(result) == 0, "Exit code should be 0 (no failures)" 159 | call_args = mock_client.finish_test_item.call_args_list 160 | finish_test_step = call_args[0][1] 161 | actual_issue = finish_test_step.get("issue", None) 162 | assert isinstance(actual_issue, Issue) 163 | expect(actual_issue.issue_type == "pb001") 164 | expect(actual_issue.comment is not None) 165 | assert_expectations() 166 | 167 | 168 | @mock.patch(REPORT_PORTAL_SERVICE) 169 | def test_external_issue(mock_client_init): 170 | """Verify skipped test with issue decorator handling. 171 | 172 | :param mock_client_init: mocked Report Portal client Pytest fixture 173 | """ 174 | mock_client = mock_client_init.return_value 175 | mock_client.start_test_item.side_effect = utils.item_id_gen 176 | mock_client.get_project_settings.side_effect = utils.project_settings 177 | 178 | variables = {"rp_bts_project": BTS_PROJECT, "rp_bts_url": BTS_URL, "rp_bts_issue_url": ISSUE_URL_PATTERN} 179 | variables.update(utils.DEFAULT_VARIABLES.items()) 180 | 181 | result = utils.run_pytest_tests(tests=["examples/test_issue_id.py"], variables=variables) 182 | 183 | assert int(result) == 1, "Exit code should be 1 (test failed)" 184 | call_args = mock_client.finish_test_item.call_args_list 185 | finish_test_step = call_args[0][1] 186 | actual_issue = finish_test_step.get("issue", None) 187 | assert isinstance(actual_issue, Issue) 188 | expect(actual_issue.issue_type == "pb001") 189 | expect(actual_issue.comment is not None) 190 | external_issues = actual_issue._external_issues 191 | expect(len(external_issues) == 1) 192 | assert_expectations() 193 | external_issue = external_issues[0] 194 | expect(external_issue["btsUrl"] == BTS_URL) 195 | expect(external_issue["btsProject"] == BTS_PROJECT) 196 | expect(external_issue["ticketId"] == test_issue_id.ID) 197 | expect(external_issue["url"] == ISSUE_URL_PATTERN.replace(ISSUE_PLACEHOLDER, test_issue_id.ID)) 198 | assert_expectations() 199 | -------------------------------------------------------------------------------- /tests/integration/test_max_name_length.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 EPAM Systems 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from unittest import mock 16 | 17 | from tests import REPORT_PORTAL_SERVICE 18 | from tests.helpers import utils 19 | 20 | 21 | @mock.patch(REPORT_PORTAL_SERVICE) 22 | def test_custom_attribute_report(mock_client_init): 23 | result = utils.run_pytest_tests(tests=["examples/test_max_item_name.py"], variables=utils.DEFAULT_VARIABLES) 24 | assert int(result) == 0, "Exit code should be 0 (no errors)" 25 | 26 | mock_client = mock_client_init.return_value 27 | start_count = mock_client.start_test_item.call_count 28 | finish_count = mock_client.finish_test_item.call_count 29 | assert start_count == finish_count == 1, 'Incorrect number of "start_test_item" or "finish_test_item" calls' 30 | 31 | call_args = mock_client.start_test_item.call_args_list 32 | step_call_args = call_args[0][1] 33 | assert len(step_call_args["name"]) == 1024, "Incorrect item name length" 34 | -------------------------------------------------------------------------------- /tests/integration/test_parameters_report.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 https://reportportal.io . 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | """This module includes integration tests for parameters report.""" 15 | 16 | from unittest import mock 17 | 18 | import pytest 19 | 20 | from examples.params.test_binary_symbol_in_parameters import BINARY_TEXT 21 | from tests import REPORT_PORTAL_SERVICE 22 | from tests.helpers import utils 23 | 24 | 25 | @mock.patch(REPORT_PORTAL_SERVICE) 26 | @pytest.mark.parametrize( 27 | ["test", "expected_params"], 28 | [ 29 | ("examples/test_simple.py", None), 30 | ("examples/params/test_in_class_parameterized.py", {"param": "param"}), 31 | ( 32 | "examples/params/test_different_parameter_types.py", 33 | {"integer": 1, "floating_point": 1.5, "boolean": True, "none": None}, 34 | ), 35 | ("examples/params/test_binary_symbol_in_parameters.py", {"text": BINARY_TEXT.replace("\0", "\\0")}), 36 | ], 37 | ) 38 | def test_parameters(mock_client_init, test, expected_params): 39 | """Verify different tests have correct parameters. 40 | 41 | :param mock_client_init: Pytest fixture 42 | :param test: a test to run 43 | :param expected_params: an expected parameter dictionary 44 | """ 45 | result = utils.run_pytest_tests(tests=[test]) 46 | assert int(result) == 0, "Exit code should be 0 (no errors)" 47 | 48 | mock_client = mock_client_init.return_value 49 | assert mock_client.start_test_item.call_count > 0, '"start_test_item" called incorrect number of times' 50 | 51 | call_args = mock_client.start_test_item.call_args_list 52 | step_call_args = call_args[-1][1] 53 | assert step_call_args["parameters"] == expected_params 54 | -------------------------------------------------------------------------------- /tests/integration/test_pass_failed_skipped.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 https://reportportal.io . 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | """This module includes integration tests for item statuses report.""" 15 | 16 | from unittest import mock 17 | 18 | import pytest 19 | 20 | from tests import REPORT_PORTAL_SERVICE 21 | from tests.helpers import utils 22 | 23 | 24 | @pytest.mark.parametrize( 25 | ("test", "expected_run_status", "expected_item_status"), 26 | [ 27 | ("examples/test_simple.py", 0, "PASSED"), 28 | ("examples/test_simple_fail.py", 1, "FAILED"), 29 | ("examples/skip/test_simple_skip.py", 0, "SKIPPED"), 30 | ], 31 | ) 32 | @mock.patch(REPORT_PORTAL_SERVICE) 33 | def test_simple_tests(mock_client_init, test, expected_run_status, expected_item_status): 34 | """Verify a simple test creates correct structure and finishes all items. 35 | 36 | Report 'None' for suites and launch due to possible parallel execution. 37 | Leave status calculation on Server. 38 | :param mock_client_init: mocked Report Portal client Pytest fixture 39 | :param test: a test to run as use case 40 | :param expected_run_status: expected pytest run status 41 | :param expected_item_status: expected result test item status 42 | """ 43 | mock_client = mock_client_init.return_value 44 | mock_client.start_test_item.side_effect = utils.item_id_gen 45 | 46 | result = utils.run_pytest_tests(tests=[test]) 47 | assert int(result) == expected_run_status, "Exit code should be " + str(expected_run_status) 48 | 49 | start_call_args = mock_client.start_test_item.call_args_list 50 | finish_call_args = mock_client.finish_test_item.call_args_list 51 | assert len(start_call_args) == len(finish_call_args), "Number of started items should be equal to finished items" 52 | 53 | for i in range(len(start_call_args)): 54 | start_test_step = start_call_args[-1 - i][1] 55 | finish_test_step = finish_call_args[i][1] 56 | 57 | assert finish_test_step["item_id"].startswith(start_test_step["name"]) 58 | if i == 0: 59 | actual_status = finish_test_step["status"] 60 | assert ( 61 | actual_status == expected_item_status 62 | ), f'Invalid item status, actual "{actual_status}", expected: "{expected_item_status}"' 63 | 64 | finish_launch_call_args = mock_client.finish_launch.call_args_list 65 | assert len(finish_launch_call_args) == 1 66 | assert "end_time" in finish_launch_call_args[0][1] 67 | assert finish_launch_call_args[0][1]["end_time"] is not None 68 | assert "status" not in finish_launch_call_args[0][1] 69 | -------------------------------------------------------------------------------- /tests/integration/test_pytest_parallel.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 https://reportportal.io . 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | """This module includes integration tests for "pytest_parallel" plugin.""" 15 | 16 | from unittest import mock 17 | 18 | import pytest 19 | 20 | from tests import REPORT_PORTAL_SERVICE 21 | from tests.helpers import utils 22 | from tests.helpers.utils import item_id_gen 23 | 24 | 25 | @mock.patch(REPORT_PORTAL_SERVICE) 26 | @pytest.mark.skip(reason="This test breaks all other tests, so only for local execution") 27 | def test_pytest_parallel_threads(mock_client_init): 28 | """Verify "pytest_parallel" plugin run tests in two threads. 29 | 30 | :param mock_client_init: Pytest fixture 31 | """ 32 | mock_client = mock_client_init.return_value 33 | mock_client.start_test_item.side_effect = item_id_gen 34 | 35 | result = utils.run_pytest_tests(tests=["examples/hierarchy"], args=["--tests-per-worker", "2"]) 36 | assert int(result) == 0, "Exit code should be 0 (no errors)" 37 | 38 | mock_client = mock_client_init.return_value 39 | 40 | assert mock_client.start_launch.call_count == 1, '"start_launch" method was not called' 41 | assert mock_client.finish_launch.call_count == 1, '"finish_launch" method was not called' 42 | 43 | finish_args = mock_client.finish_launch.call_args_list 44 | assert finish_args[0][1]["status"] in ("PASSED", None), "Launch failed" 45 | launch_end_time = finish_args[0][1]["end_time"] 46 | assert launch_end_time is not None and int(launch_end_time) > 0, "Launch end time is empty" 47 | -------------------------------------------------------------------------------- /tests/integration/test_suite_hierarchy.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 https://reportportal.io . 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | """This module includes integration tests for different suite hierarchy.""" 15 | 16 | from unittest import mock 17 | 18 | import pytest 19 | 20 | from tests import REPORT_PORTAL_SERVICE 21 | from tests.helpers import utils 22 | from tests.integration import HIERARCHY_TEST_PARAMETERS 23 | 24 | 25 | def verify_start_item_parameters(mock_client, expected_items): 26 | assert mock_client.start_test_item.call_count == len( 27 | expected_items 28 | ), '"start_test_item" method was called incorrect number of times' 29 | 30 | call_args = mock_client.start_test_item.call_args_list 31 | for i, call in enumerate(call_args): 32 | start_kwargs = call[1] 33 | assert start_kwargs["name"] == expected_items[i]["name"] 34 | assert start_kwargs["item_type"] == expected_items[i]["item_type"] 35 | verification = expected_items[i]["parent_item_id"] 36 | assert verification(start_kwargs["parent_item_id"]) 37 | 38 | 39 | @pytest.mark.parametrize(("test", "variables", "expected_items"), HIERARCHY_TEST_PARAMETERS) 40 | @mock.patch(REPORT_PORTAL_SERVICE) 41 | def test_rp_hierarchy_parameters(mock_client_init, test, variables, expected_items): 42 | """Verify suite hierarchy with `rp_hierarchy_dirs=True`. 43 | 44 | :param mock_client_init: Pytest fixture 45 | """ 46 | mock_client = mock_client_init.return_value 47 | mock_client.start_test_item.side_effect = utils.item_id_gen 48 | 49 | result = utils.run_pytest_tests(tests=test, variables=variables) 50 | assert int(result) == 0, "Exit code should be 0 (no errors)" 51 | 52 | verify_start_item_parameters(mock_client, expected_items) 53 | -------------------------------------------------------------------------------- /tests/integration/test_threads_logs.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 https://reportportal.io . 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | from unittest import mock 15 | 16 | from tests import REPORT_PORTAL_SERVICE 17 | from tests.helpers import utils 18 | 19 | 20 | @mock.patch(REPORT_PORTAL_SERVICE) 21 | def test_rp_thread_logs_reporting(mock_client_init): 22 | """Verify logs from threads are sent to correct items`. 23 | 24 | :param mock_client_init: Pytest fixture 25 | """ 26 | mock_client = mock_client_init.return_value 27 | mock_thread_client = mock_client.clone() 28 | 29 | def init_thread_client(*_, **__): 30 | from reportportal_client import set_current 31 | 32 | set_current(mock_thread_client) 33 | return mock_thread_client 34 | 35 | mock_client.clone.side_effect = init_thread_client 36 | result = utils.run_tests_with_client(mock_client, ["examples/threads/"], args=["--rp-thread-logging"]) 37 | 38 | assert int(result) == 0, "Exit code should be 0 (no errors)" 39 | assert mock_client.start_launch.call_count == 1, '"start_launch" method was not called' 40 | assert mock_client.log.call_count == 1 41 | assert mock_thread_client.log.call_count == 2 42 | -------------------------------------------------------------------------------- /tests/unit/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 https://reportportal.io . 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | """This package contains unit tests for the project.""" 15 | -------------------------------------------------------------------------------- /tests/unit/conftest.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 https://reportportal.io . 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | """This module contains common Pytest fixtures and hooks for unit tests.""" 15 | 16 | # noinspection PyUnresolvedReferences 17 | from unittest import mock 18 | 19 | import py 20 | from _pytest.config import Config 21 | from _pytest.main import Session 22 | from pluggy._tracing import TagTracer 23 | from pytest import Module, fixture 24 | from reportportal_client import RPLogger 25 | 26 | from pytest_reportportal.config import AgentConfig 27 | from pytest_reportportal.service import PyTestService 28 | from tests import REPORT_PORTAL_SERVICE 29 | 30 | ITEM_PATH = py.path.local("examples/test_simple.py") 31 | 32 | 33 | @fixture 34 | def logger(): 35 | """Prepare instance of the RPLogger for testing.""" 36 | return RPLogger("pytest_reportportal.test") 37 | 38 | 39 | @fixture() 40 | def mocked_config(): 41 | """Mock Pytest config for testing.""" 42 | mocked_config = mock.create_autospec(Config) 43 | 44 | mocked_config.getoption_side_effects = {"--collect-only": False, "--setup-plan": False, "rp_log_level": "debug"} 45 | 46 | def getoption_side_effect(name, default=None): 47 | return mocked_config.getoption_side_effects.get(name, default if default else mock.Mock()) 48 | 49 | mocked_config._reporter_config = mock.Mock() 50 | mocked_config.getoption.side_effect = getoption_side_effect 51 | mocked_config._rp_enabled = True 52 | mocked_config.rootdir = py.path.local("/path/to") 53 | mocked_config.trace = TagTracer().get("root") 54 | mocked_config.pluginmanager = mock.Mock() 55 | mocked_config.option = mock.create_autospec(Config) 56 | mocked_config.option.rp_project = "default_personal" 57 | mocked_config.option.rp_endpoint = "http://docker.local:8080/" 58 | mocked_config.option.rp_api_key = mock.sentinel.rp_api_key 59 | mocked_config.option.rp_log_batch_size = -1 60 | mocked_config.option.retries = -1 61 | mocked_config.option.rp_hierarchy_dirs_level = "0" 62 | mocked_config.option.rp_rerun = False 63 | mocked_config.option.rp_launch_timeout = -1 64 | mocked_config.option.rp_thread_logging = True 65 | mocked_config.option.rp_launch_uuid_print = "False" 66 | mocked_config.option.rp_launch_uuid_print_output = "STDOUT" 67 | mocked_config.option.rp_client_type = "SYNC" 68 | mocked_config.option.rp_report_fixtures = "False" 69 | mocked_config.option.rp_hierarchy_code = "False" 70 | mocked_config.option.rp_hierarchy_dirs = "False" 71 | mocked_config.option.rp_hierarchy_test_file = "True" 72 | mocked_config.option.rp_skip_connection_test = "False" 73 | return mocked_config 74 | 75 | 76 | @fixture() 77 | def mocked_session(mocked_config): 78 | """Mock Pytest session for testing.""" 79 | mocked_session = mock.create_autospec(Session) 80 | mocked_session.config = mocked_config 81 | return mocked_session 82 | 83 | 84 | @fixture() 85 | def mocked_module(mocked_session): 86 | """Mock Pytest Module for testing.""" 87 | mocked_module = mock.create_autospec(Module) 88 | mocked_module.parent = mocked_session 89 | mocked_module.name = "module" 90 | mocked_module.fspath = ITEM_PATH 91 | return mocked_module 92 | 93 | 94 | @fixture() 95 | def mocked_item(mocked_session, mocked_module): 96 | """Mock Pytest item for testing.""" 97 | test_item = mock.Mock() 98 | test_item.session = mocked_session 99 | test_item.fspath = ITEM_PATH 100 | name = "test_item" 101 | test_item.name = name 102 | test_item.originalname = name 103 | test_item.parent = mocked_module 104 | return test_item 105 | 106 | 107 | @fixture() 108 | def rp_service(mocked_config): 109 | """Prepare instance of the PyTestService for testing.""" 110 | service = PyTestService(AgentConfig(mocked_config)) 111 | with mock.patch(REPORT_PORTAL_SERVICE + ".get_project_settings"): 112 | service.start() 113 | return service 114 | -------------------------------------------------------------------------------- /tests/unit/test_config.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 https://reportportal.io . 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | import pytest 15 | 16 | from pytest_reportportal.config import AgentConfig 17 | 18 | 19 | @pytest.mark.parametrize( 20 | ["verify_ssl", "expected_result"], 21 | [ 22 | ("True", True), 23 | ("False", False), 24 | ("true", True), 25 | ("false", False), 26 | (True, True), 27 | (False, False), 28 | ("path/to/certificate", "path/to/certificate"), 29 | (None, True), 30 | ], 31 | ) 32 | def test_verify_ssl_true(mocked_config, verify_ssl, expected_result): 33 | mocked_config.getini.side_effect = lambda x: verify_ssl if x == "rp_verify_ssl" else None 34 | config = AgentConfig(mocked_config) 35 | 36 | assert config.rp_verify_ssl == expected_result 37 | -------------------------------------------------------------------------------- /tests/unit/test_service.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 https://reportportal.io . 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # https://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License 13 | 14 | """This module includes unit tests for the service.py module.""" 15 | 16 | from delayed_assert import assert_expectations, expect 17 | 18 | 19 | def test_get_item_parameters(mocked_item, rp_service): 20 | """Test that parameters are returned in a way supported by the client.""" 21 | mocked_item.callspec.params = {"param": "param_value"} 22 | 23 | expect(rp_service._get_parameters(mocked_item) == {"param": "param_value"}) 24 | 25 | delattr(mocked_item, "callspec") 26 | expect(rp_service._get_parameters(mocked_item) is None) 27 | 28 | assert_expectations() 29 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | isolated_build = True 3 | envlist = 4 | pep 5 | nobdd 6 | py38 7 | py39 8 | py310 9 | py311 10 | py312 11 | py313 12 | 13 | [testenv] 14 | deps = 15 | -rrequirements.txt 16 | -rrequirements-dev.txt 17 | -rrequirements-dev-bdd.txt 18 | 19 | setenv = 20 | AGENT_NO_ANALYTICS = 1 21 | 22 | commands = pytest --cov={envsitepackagesdir}/pytest_reportportal --cov-report=xml tests/ -s -vv 23 | 24 | [testenv:nobdd] 25 | deps = 26 | -rrequirements.txt 27 | -rrequirements-dev.txt 28 | 29 | setenv = 30 | AGENT_NO_ANALYTICS = 1 31 | 32 | commands = pytest tests/ -s -vv --ignore tests/integration/test_bdd.py 33 | 34 | [testenv:pep] 35 | skip_install = True 36 | deps = pre-commit>=1.19.0 37 | commands = pre-commit run --all-files --show-diff-on-failure 38 | 39 | [gh-actions] 40 | python = 41 | 3.8: py38 42 | 3.9: py39 43 | 3.10: pep, nobdd, py310 44 | 3.11: py311 45 | 3.12: py312 46 | 3.13: py313 47 | --------------------------------------------------------------------------------