Skip to content

Commit 1fef4a0

Browse files
committed
fix: count skipped tests in accuracy executions
1 parent d894941 commit 1fef4a0

File tree

3 files changed

+69
-19
lines changed

3 files changed

+69
-19
lines changed

CHANGELOG.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ v3.6.1
66

77
*Release date: In development*
88

9+
- Fix accuracy tag to exclude skipped executions from total executions count
10+
- Add `after_accuracy_scenario` hook to allow custom behavior after accuracy scenario execution
11+
912
v3.6.0
1013
------
1114

docs/ai_utils.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,3 +157,19 @@ For example, to store accuracy data for greetings, you can do the following in a
157157
158158
This way, during each execution of the scenario, Toolium will use the corresponding data from the accuracy data set
159159
based on the execution index.
160+
161+
after_accuracy_scenario method
162+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
163+
164+
You can monkey-patch the `after_accuracy_scenario` method in `toolium.utils.ai_utils.accuracy` module to implement
165+
custom behavior after accuracy scenario execution, like calling Allure `after_scenario` method.
166+
167+
.. code-block:: python
168+
169+
from toolium.utils.ai_utils import accuracy
170+
171+
def custom_after_accuracy_scenario(context, scenario):
172+
context.allure.after_scenario(context, scenario)
173+
174+
# Monkey-patch the hook
175+
accuracy.after_accuracy_scenario = custom_after_accuracy_scenario

toolium/utils/ai_utils/accuracy.py

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ def patch_scenario_with_accuracy(context, scenario, data_key_suffix, accuracy=0.
8989
"""
9090
def scenario_run_with_accuracy(context, scenario_run, scenario, *args, **kwargs):
9191
# Execute the scenario multiple times and count passed executions
92-
passed_executions = 0
92+
passed_executions = skipped_executions = 0
9393
# Copy scenario steps to avoid modifications in each execution, especially when using behave variables
9494
# transformation, like map_param and replace_param methods
9595
orig_steps = deepcopy(scenario.steps)
@@ -99,30 +99,50 @@ def scenario_run_with_accuracy(context, scenario_run, scenario, *args, **kwargs)
9999
# Restore original steps before each execution
100100
scenario.steps = deepcopy(orig_steps)
101101
if not scenario_run(*args, **kwargs):
102-
passed_executions += 1
103-
status = "PASSED"
102+
if scenario.status == Status.skipped:
103+
skipped_executions += 1
104+
status = "SKIPPED"
105+
else:
106+
passed_executions += 1
107+
status = "PASSED"
104108
else:
105109
status = "FAILED"
106110
print(f"ACCURACY SCENARIO {status}: execution {execution+1}/{executions}")
107111
context.logger.info(f"Accuracy scenario execution {status} ({execution+1}/{executions})")
108112

109-
# Calculate scenario accuracy
110-
scenario_accuracy = passed_executions / executions
111-
has_passed = scenario_accuracy >= accuracy
112-
final_status = 'PASSED' if has_passed else 'FAILED'
113-
print(f"\nACCURACY SCENARIO {final_status}: {executions} executions,"
114-
f" accuracy {scenario_accuracy} >= {accuracy}")
115-
final_message = (f"Accuracy scenario {final_status} after {executions} executions with"
116-
f" accuracy {scenario_accuracy} >= {accuracy}")
117-
118-
# Set final scenario status
119-
if has_passed:
120-
context.logger.info(final_message)
121-
scenario.set_status(Status.passed)
113+
114+
if executions == skipped_executions:
115+
run_response = False # Run method returns true only when failed
116+
context.logger.info("All accuracy scenario executions are skipped")
122117
else:
123-
context.logger.error(final_message)
124-
scenario.set_status(Status.failed)
125-
return not has_passed # Run method returns true when failed
118+
# Calculate scenario accuracy
119+
scenario_accuracy = passed_executions / (executions - skipped_executions)
120+
has_passed = scenario_accuracy >= accuracy
121+
run_response = not has_passed # Run method returns true only when failed
122+
final_status = 'PASSED' if has_passed else 'FAILED'
123+
print(f"\nACCURACY SCENARIO {final_status}: {executions} executions,"
124+
f" accuracy {scenario_accuracy} >= {accuracy}")
125+
final_message = (f"Accuracy scenario {final_status} after {executions} executions with"
126+
f" accuracy {scenario_accuracy} >= {accuracy}"
127+
f" ({passed_executions} passed, {skipped_executions} skipped,"
128+
f" {executions - passed_executions - skipped_executions} failed)")
129+
130+
# Set final scenario status
131+
if has_passed:
132+
context.logger.info(final_message)
133+
scenario.set_status(Status.passed)
134+
else:
135+
context.logger.error(final_message)
136+
scenario.set_status(Status.failed)
137+
scenario.exception = AssertionError(final_message)
138+
139+
# Clean accuracy execution data from context
140+
context.storage.pop("accuracy_execution_data", None)
141+
context.storage.pop("accuracy_execution_index", None)
142+
143+
after_accuracy_scenario(context, scenario)
144+
145+
return run_response
126146

127147
scenario_run = scenario.run
128148
scenario.run = functools.partial(scenario_run_with_accuracy, context, scenario_run, scenario)
@@ -190,3 +210,14 @@ def store_execution_data(context, execution, data_key_suffix):
190210
context.storage["accuracy_execution_index"] = execution
191211
context.logger.info(f"Stored accuracy data for execution {execution+1} in"
192212
f" accuracy_execution_data: {execution_data}")
213+
214+
215+
def after_accuracy_scenario(context, scenario):
216+
"""Hook called after accuracy scenario execution.
217+
Monkey-patch this method to implement custom behavior after accuracy scenario execution, like calling Allure
218+
after_scenario method.
219+
220+
:param context: behave context
221+
:param scenario: behave scenario
222+
"""
223+
pass

0 commit comments

Comments
 (0)