Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions examples/test_case_id/test_case_id_decorator_use_index_false.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""A simple example test with Test Case ID decorator using parameter values."""

# Copyright (c) 2023 https://reportportal.io .
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License

import pytest

TEST_CASE_ID = "ISSUE-USE-INDEX-FALSE"


@pytest.mark.parametrize(("param1", "param2"), [("value1", "value2")])
@pytest.mark.tc_id(TEST_CASE_ID, parameterized=True, use_index=False)
def test_case_id_decorator(param1, param2):
assert True
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""A simple example test with Test Case ID decorator using parameter indices with selected params."""

# Copyright (c) 2023 https://reportportal.io .
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License

import pytest

TEST_CASE_ID = "ISSUE-USE-INDEX-PARTIAL"


@pytest.mark.parametrize(("param1", "param2"), [("value1", "value2")])
@pytest.mark.tc_id(TEST_CASE_ID, parameterized=True, params=["param1"], use_index=True)
def test_case_id_decorator(param1, param2):
assert True
24 changes: 24 additions & 0 deletions examples/test_case_id/test_case_id_decorator_use_index_true.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""A simple example test with Test Case ID decorator using parameter indices."""

# Copyright (c) 2023 https://reportportal.io .
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License

import pytest

TEST_CASE_ID = "ISSUE-USE-INDEX-TRUE"


@pytest.mark.parametrize(("param1", "param2"), [("value1", "value2")])
@pytest.mark.tc_id(TEST_CASE_ID, parameterized=True, use_index=True)
def test_case_id_decorator(param1, param2):
assert True
24 changes: 23 additions & 1 deletion pytest_reportportal/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -599,18 +599,26 @@ def _get_code_ref(self, item: Item) -> str:

def _get_test_case_id(self, mark, leaf: Dict[str, Any]) -> str:
parameters: Optional[Dict[str, Any]] = leaf.get("parameters", None)
parameters_indices: Optional[Dict[str, Any]] = leaf.get("parameters_indices") or {}
parameterized = True
selected_params: Optional[List[str]] = None
use_index = False
if mark is not None:
parameterized = mark.kwargs.get("parameterized", False)
selected_params: Optional[Union[str, List[str]]] = mark.kwargs.get("params", None)
use_index = mark.kwargs.get("use_index", False)
if selected_params is not None and not isinstance(selected_params, list):
selected_params = [selected_params]

param_str = None
if parameterized and parameters is not None and len(parameters) > 0:
if selected_params is not None and len(selected_params) > 0:
param_list = [str(parameters.get(param, None)) for param in selected_params]
if use_index:
param_list = [str((param, parameters_indices.get(param, None))) for param in selected_params]
else:
param_list = [str(parameters.get(param, None)) for param in selected_params]
elif use_index:
param_list = [str(param) for param in parameters_indices.items()]
else:
param_list = [str(param) for param in parameters.values()]
param_str = "[{}]".format(",".join(sorted(param_list)))
Expand Down Expand Up @@ -729,6 +737,19 @@ def _get_parameters(self, item) -> Optional[Dict[str, Any]]:
return None
return {str(k): v.replace("\0", "\\0") if isinstance(v, str) else v for k, v in params.items()}

def _get_parameters_indices(self, item) -> Optional[Dict[str, Any]]:
"""
Get params indices of item.

:param item: Pytest.Item
:return: dict of params indices
"""
indices = item.callspec.indices if hasattr(item, "callspec") else None
if not indices:
return None

return indices

def _process_test_case_id(self, leaf: Dict[str, Any]) -> str:
"""
Process Test Case ID if set.
Expand Down Expand Up @@ -793,6 +814,7 @@ def _process_metadata_item_start(self, leaf: Dict[str, Any]) -> None:
leaf["name"] = self._process_item_name(leaf)
leaf["description"] = self._get_item_description(item)
leaf["parameters"] = self._get_parameters(item)
leaf["parameters_indices"] = self._get_parameters_indices(item)
leaf["code_ref"] = self._get_code_ref(item)
leaf["test_case_id"] = self._process_test_case_id(leaf)
leaf["issue"] = self._process_issue(item)
Expand Down
77 changes: 77 additions & 0 deletions tests/integration/test_case_id_use_index_report.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Copyright (c) 2023 https://reportportal.io .
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License

"""This module includes integration tests for Test Case ID report with use_index parameter."""

from unittest import mock

import pytest

from examples.test_case_id import (
test_case_id_decorator_use_index_false,
test_case_id_decorator_use_index_partial_params,
test_case_id_decorator_use_index_true,
)
from tests import REPORT_PORTAL_SERVICE
from tests.helpers import utils


@mock.patch(REPORT_PORTAL_SERVICE)
@pytest.mark.parametrize(
["test", "expected_id"],
[
# Test use_index=True: should use parameter indices instead of values
# Format should be: ('param1', 0),('param2', 0) instead of value1,value2
(
"examples/test_case_id/test_case_id_decorator_use_index_true.py",
test_case_id_decorator_use_index_true.TEST_CASE_ID + "[('param1', 0),('param2', 0)]",
),
# Test use_index=False: should use parameter values (default behavior)
(
"examples/test_case_id/test_case_id_decorator_use_index_false.py",
test_case_id_decorator_use_index_false.TEST_CASE_ID + "[value1,value2]",
),
# Test use_index=True with selected params: should use index for selected param only
# Should be ('param1', 0) instead of value1
(
"examples/test_case_id/test_case_id_decorator_use_index_partial_params.py",
test_case_id_decorator_use_index_partial_params.TEST_CASE_ID + "[('param1', 0)]",
),
],
)
def test_use_index_parameters(mock_client_init, test, expected_id):
"""Verify the use_index parameter in Test Case ID functionality.

This test verifies that the new use_index parameter works correctly for parameterized tests.
When use_index=True, the test case ID should include parameter indices instead of parameter values.
This is useful for scenarios where parameter values might change between test runs but the indices
remain constant, ensuring that retry groups are properly maintained.

The test covers:
1. use_index=True with all parameters - should use (param_name, index) format
2. use_index=False - should use parameter values (default behavior)
3. use_index=True with selected parameters - should use indices only for selected params

:param mock_client_init: Pytest fixture for mocking the ReportPortal client
:param test: a test file path to run
:param expected_id: the expected Test Case ID format
"""
result = utils.run_pytest_tests(tests=[test])
assert int(result) == 0, "Exit code should be 0 (no errors)"

mock_client = mock_client_init.return_value
assert mock_client.start_test_item.call_count > 0, '"start_test_item" called incorrect number of times'

call_args = mock_client.start_test_item.call_args_list
step_call_args = call_args[-1][1]
assert step_call_args["test_case_id"] == expected_id