Skip to content

Commit 67b8e57

Browse files
committed
Add custom Test Case ID
1 parent 23d21a9 commit 67b8e57

File tree

6 files changed

+149
-2
lines changed

6 files changed

+149
-2
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Feature: Test dummy scenario
2+
3+
@tc_id:my_tc_id
4+
Scenario: The scenario
5+
Given I have empty step
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
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 <str>
7+
Then I emit number <parameters> on level info
8+
9+
Examples:
10+
| str | parameters |
11+
| "first" | 123 |
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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")
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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)

pytest_reportportal/service.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,6 +1189,16 @@ def _get_scenario_code_ref(self, scenario: Scenario, scenario_template: Optional
11891189
return code_ref
11901190

11911191
def _get_scenario_test_case_id(self, leaf: Dict[str, Any]) -> str:
1192+
attributes = leaf.get("attributes", [])
1193+
params: Optional[Dict[str, str]] = leaf.get("parameters", None)
1194+
for attribute in attributes:
1195+
if attribute.get("key", None) == "tc_id":
1196+
tc_id = attribute["value"]
1197+
params_str = ""
1198+
if params:
1199+
params_str = ";".join([f"{k}:{v}" for k, v in sorted(params.items())])
1200+
params_str = f"[{params_str}]"
1201+
return f"{tc_id}{params_str}"
11921202
return leaf["code_ref"]
11931203

11941204
def _process_scenario_metadata(self, leaf: Dict[str, Any]) -> None:
@@ -1203,7 +1213,7 @@ def _process_scenario_metadata(self, leaf: Dict[str, Any]) -> None:
12031213
).rstrip("\n")
12041214
leaf["description"] = description if description else None
12051215
scenario_template = self._get_scenario_template(scenario)
1206-
if scenario_template:
1216+
if scenario_template and scenario_template.templated:
12071217
parameters = self._get_scenario_parameters_from_template(scenario)
12081218
leaf["parameters"] = parameters
12091219
if parameters:
@@ -1213,8 +1223,8 @@ def _process_scenario_metadata(self, leaf: Dict[str, Any]) -> None:
12131223
else:
12141224
leaf["description"] = parameters_str
12151225
leaf["code_ref"] = self._get_scenario_code_ref(scenario, scenario_template)
1216-
leaf["test_case_id"] = self._get_scenario_test_case_id(leaf)
12171226
leaf["attributes"] = self._process_bdd_attributes(scenario)
1227+
leaf["test_case_id"] = self._get_scenario_test_case_id(leaf)
12181228

12191229
def _finish_bdd_step(self, leaf: Dict[str, Any], status: str) -> None:
12201230
if leaf["exec"] != ExecStatus.IN_PROGRESS:

tests/integration/test_bdd.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,3 +1037,60 @@ def test_data_table_parameter_steps(mock_client_init):
10371037
finish_calls = mock_client.finish_test_item.call_args_list
10381038
for call in finish_calls:
10391039
assert call[1]["status"] == "PASSED"
1040+
1041+
1042+
@mock.patch(REPORT_PORTAL_SERVICE)
1043+
def test_scenario_outline_test_case_id(mock_client_init):
1044+
mock_client = setup_mock_for_logging(mock_client_init)
1045+
result = utils.run_pytest_tests(tests=["examples/bdd/step_defs/scenario_outline_test_case_id_steps.py"])
1046+
assert int(result) == 0, "Exit code should be 0 (no errors)"
1047+
1048+
# Verify first scenario with parameters includes the test case ID
1049+
scenario_call = mock_client.start_test_item.call_args_list[0]
1050+
assert (
1051+
scenario_call[1]["name"]
1052+
== "Feature: Basic test with parameters - Scenario Outline: Test with different parameters"
1053+
)
1054+
assert scenario_call[1]["item_type"] == "STEP"
1055+
assert (
1056+
scenario_call[1]["code_ref"]
1057+
== "features/scenario_outline_test_case_id.feature/[EXAMPLE:Test with different parameters"
1058+
'[parameters:123;str:"first"]]'
1059+
)
1060+
assert scenario_call[1]["parameters"] == {"str": '"first"', "parameters": "123"}
1061+
1062+
# Verify the test case ID is correctly reported using the tag instead of code_ref
1063+
assert scenario_call[1]["test_case_id"] == 'outline_tc_id[parameters:123;str:"first"]'
1064+
1065+
# Verify all steps pass
1066+
finish_calls = mock_client.finish_test_item.call_args_list
1067+
for call in finish_calls:
1068+
assert call[1]["status"] == "PASSED"
1069+
1070+
1071+
@mock.patch(REPORT_PORTAL_SERVICE)
1072+
def test_custom_test_case_id(mock_client_init):
1073+
mock_client = setup_mock_for_logging(mock_client_init)
1074+
result = utils.run_pytest_tests(tests=["examples/bdd/step_defs/custom_test_case_id_steps.py"])
1075+
assert int(result) == 0, "Exit code should be 0 (no errors)"
1076+
1077+
# Verify scenario includes the test case ID
1078+
scenario_call = mock_client.start_test_item.call_args_list[0]
1079+
assert scenario_call[1]["name"] == "Feature: Test dummy scenario - Scenario: The scenario"
1080+
assert scenario_call[1]["item_type"] == "STEP"
1081+
assert scenario_call[1]["code_ref"] == "features/custom_test_case_id.feature/[SCENARIO:The scenario]"
1082+
1083+
# Verify the test case ID is correctly reported using the tag instead of code_ref
1084+
assert scenario_call[1]["test_case_id"] == "my_tc_id"
1085+
1086+
# Verify step info
1087+
step_call = mock_client.start_test_item.call_args_list[1]
1088+
assert step_call[0][0] == "Given I have empty step"
1089+
assert step_call[0][2] == "step"
1090+
assert step_call[1]["parent_item_id"] == scenario_call[1]["name"] + "_1"
1091+
assert step_call[1]["has_stats"] is False
1092+
1093+
# Verify all steps pass
1094+
finish_calls = mock_client.finish_test_item.call_args_list
1095+
for call in finish_calls:
1096+
assert call[1]["status"] == "PASSED"

0 commit comments

Comments
 (0)