baldertest 0.1.0b8__py3-none-any.whl → 0.1.0b10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- _balder/_version.py +1 -1
- _balder/balder_session.py +5 -3
- _balder/collector.py +117 -8
- _balder/console/balder.py +1 -1
- _balder/controllers/device_controller.py +1 -1
- _balder/controllers/feature_controller.py +38 -17
- _balder/controllers/normal_scenario_setup_controller.py +5 -12
- _balder/controllers/scenario_controller.py +91 -1
- _balder/decorator_fixture.py +4 -7
- _balder/decorator_for_vdevice.py +4 -6
- _balder/decorator_parametrize.py +31 -0
- _balder/decorator_parametrize_by_feature.py +36 -0
- _balder/exceptions.py +6 -0
- _balder/executor/basic_executable_executor.py +126 -0
- _balder/executor/basic_executor.py +6 -95
- _balder/executor/executor_tree.py +22 -8
- _balder/executor/parametrized_testcase_executor.py +52 -0
- _balder/executor/scenario_executor.py +10 -2
- _balder/executor/setup_executor.py +40 -2
- _balder/executor/testcase_executor.py +42 -9
- _balder/executor/unresolved_parametrized_testcase_executor.py +209 -0
- _balder/executor/variation_executor.py +30 -51
- _balder/fixture_definition_scope.py +19 -0
- _balder/fixture_execution_level.py +22 -0
- _balder/fixture_manager.py +169 -182
- _balder/fixture_metadata.py +26 -0
- _balder/parametrization.py +75 -0
- _balder/solver.py +51 -31
- _balder/testresult.py +38 -6
- balder/__init__.py +6 -0
- balder/exceptions.py +4 -3
- balder/parametrization.py +8 -0
- {baldertest-0.1.0b8.dist-info → baldertest-0.1.0b10.dist-info}/METADATA +1 -1
- {baldertest-0.1.0b8.dist-info → baldertest-0.1.0b10.dist-info}/RECORD +38 -28
- {baldertest-0.1.0b8.dist-info → baldertest-0.1.0b10.dist-info}/WHEEL +1 -1
- {baldertest-0.1.0b8.dist-info → baldertest-0.1.0b10.dist-info}/LICENSE +0 -0
- {baldertest-0.1.0b8.dist-info → baldertest-0.1.0b10.dist-info}/entry_points.txt +0 -0
- {baldertest-0.1.0b8.dist-info → baldertest-0.1.0b10.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import inspect
|
|
4
|
+
from typing import List, Type, Any, Dict, Iterable, TYPE_CHECKING
|
|
5
|
+
import types
|
|
6
|
+
from graphlib import TopologicalSorter
|
|
7
|
+
from collections import OrderedDict
|
|
8
|
+
|
|
9
|
+
from _balder.executor.basic_executor import BasicExecutor
|
|
10
|
+
from _balder.executor.parametrized_testcase_executor import ParametrizedTestcaseExecutor
|
|
11
|
+
from _balder.parametrization import Parameter
|
|
12
|
+
from _balder.previous_executor_mark import PreviousExecutorMark
|
|
13
|
+
from _balder.testresult import BranchBodyResult
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from _balder.executor.variation_executor import VariationExecutor
|
|
17
|
+
from _balder.scenario import Scenario
|
|
18
|
+
from _balder.setup import Setup
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class UnresolvedParametrizedTestcaseExecutor(BasicExecutor):
|
|
22
|
+
"""
|
|
23
|
+
This executor class represents a group of dynamically parametrized tests.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(
|
|
27
|
+
self,
|
|
28
|
+
testcase: callable,
|
|
29
|
+
parent: VariationExecutor,
|
|
30
|
+
static_parameters: Dict[str, Any] = None,
|
|
31
|
+
) -> None:
|
|
32
|
+
super().__init__()
|
|
33
|
+
|
|
34
|
+
self._base_testcase_callable = testcase
|
|
35
|
+
self._parent_executor = parent
|
|
36
|
+
|
|
37
|
+
# holds the specific static parameters for this unresolved group
|
|
38
|
+
self._static_parameters = static_parameters if static_parameters is not None else {}
|
|
39
|
+
|
|
40
|
+
# holds the dynamically created testcase executors as soon as this executor is entered
|
|
41
|
+
self._testcase_executors = None
|
|
42
|
+
|
|
43
|
+
# contains the result object for the BODY part of this branch
|
|
44
|
+
self.body_result = BranchBodyResult(self)
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def parent_executor(self) -> VariationExecutor:
|
|
48
|
+
return self._parent_executor
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def base_testcase_callable(self) -> callable:
|
|
52
|
+
"""returns the testcase function"""
|
|
53
|
+
return self._base_testcase_callable
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def all_child_executors(self) -> List[ParametrizedTestcaseExecutor]:
|
|
57
|
+
return self.get_testcase_executors()
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def base_testcase_obj(self) -> Scenario:
|
|
61
|
+
"""
|
|
62
|
+
return the testcase Scenario this testcase is defined in
|
|
63
|
+
"""
|
|
64
|
+
return self.parent_executor.cur_scenario_class
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def base_instance(self) -> object:
|
|
68
|
+
"""
|
|
69
|
+
returns the base class instance to which this executor instance belongs"""
|
|
70
|
+
return self._base_testcase_callable
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def parametrization_has_been_resolved(self) -> bool:
|
|
74
|
+
"""returns true if the parametrization has been resolved"""
|
|
75
|
+
return self._testcase_executors is not None
|
|
76
|
+
|
|
77
|
+
def has_runnable_tests(self, consider_discarded_too=False) -> bool:
|
|
78
|
+
"""
|
|
79
|
+
This method returns true if this executor element is runnable. The method returns true if this element has
|
|
80
|
+
`prev_mark=RUNNABLE` and minimum one of its children has `prev_mark=RUNNABLE` too.
|
|
81
|
+
|
|
82
|
+
:param consider_discarded_too: True if the method allows DISCARDED elements too
|
|
83
|
+
"""
|
|
84
|
+
if self.parametrization_has_been_resolved:
|
|
85
|
+
return super().has_runnable_tests(consider_discarded_too=consider_discarded_too)
|
|
86
|
+
|
|
87
|
+
allowed_prev_marks = [PreviousExecutorMark.RUNNABLE]
|
|
88
|
+
|
|
89
|
+
if consider_discarded_too:
|
|
90
|
+
allowed_prev_marks.append(PreviousExecutorMark.DISCARDED)
|
|
91
|
+
|
|
92
|
+
if self.prev_mark not in allowed_prev_marks:
|
|
93
|
+
return False
|
|
94
|
+
return True
|
|
95
|
+
|
|
96
|
+
def get_all_base_instances_of_this_branch(
|
|
97
|
+
self, with_type: Type[Setup] | Type[Scenario] | Type[types.FunctionType],
|
|
98
|
+
only_runnable_elements: bool = True) -> List[Setup | Scenario | object]:
|
|
99
|
+
"""
|
|
100
|
+
returns itself if the type matches, otherwise an empty list
|
|
101
|
+
"""
|
|
102
|
+
# todo
|
|
103
|
+
if isinstance(self.base_instance, with_type):
|
|
104
|
+
return [self.base_instance]
|
|
105
|
+
return []
|
|
106
|
+
|
|
107
|
+
def get_covered_by_element(self) -> List[Scenario | callable]:
|
|
108
|
+
"""
|
|
109
|
+
This method returns a list of elements where the whole scenario is covered from. This means, that the whole
|
|
110
|
+
test methods in this scenario are already be covered from every single element in the list.
|
|
111
|
+
"""
|
|
112
|
+
all_covered_by_data = []
|
|
113
|
+
scenario_executor = self.parent_executor.parent_executor
|
|
114
|
+
scenario_class = scenario_executor.base_scenario_class
|
|
115
|
+
covered_by_dict_resolved = scenario_executor.get_covered_by_dict()
|
|
116
|
+
if self.base_testcase_callable in covered_by_dict_resolved.keys():
|
|
117
|
+
all_covered_by_data += covered_by_dict_resolved[self.base_testcase_callable]
|
|
118
|
+
if scenario_class in covered_by_dict_resolved.keys():
|
|
119
|
+
all_covered_by_data += covered_by_dict_resolved[scenario_class]
|
|
120
|
+
return all_covered_by_data
|
|
121
|
+
|
|
122
|
+
def get_testcase_executors(self) -> List[ParametrizedTestcaseExecutor | UnresolvedParametrizedTestcaseExecutor]:
|
|
123
|
+
"""returns all sub testcase executors that belongs to this variation-executor"""
|
|
124
|
+
if self._testcase_executors is None:
|
|
125
|
+
return [self]
|
|
126
|
+
return self._testcase_executors
|
|
127
|
+
|
|
128
|
+
def resolve_dynamic_parametrization(self):
|
|
129
|
+
"""
|
|
130
|
+
resolves the dynamic parametrization - should be called when setup features are active in the scenario
|
|
131
|
+
"""
|
|
132
|
+
self._testcase_executors = []
|
|
133
|
+
|
|
134
|
+
parametrization = self.get_parametrization()
|
|
135
|
+
if parametrization:
|
|
136
|
+
for cur_parametrization in parametrization:
|
|
137
|
+
self._testcase_executors.append(
|
|
138
|
+
ParametrizedTestcaseExecutor(
|
|
139
|
+
self._base_testcase_callable,
|
|
140
|
+
parent=self.parent_executor,
|
|
141
|
+
parametrization=cur_parametrization,
|
|
142
|
+
unresolved_group_obj=self
|
|
143
|
+
)
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
def get_parametrization(self) -> List[OrderedDict[str, Any]] | None:
|
|
147
|
+
"""
|
|
148
|
+
returns all parametrization elements that belongs to this group executor
|
|
149
|
+
"""
|
|
150
|
+
scenario_controller = self.parent_executor.parent_executor.base_scenario_controller
|
|
151
|
+
dynamic_parametrization = scenario_controller.get_parametrization_for(self._base_testcase_callable,
|
|
152
|
+
static=False)
|
|
153
|
+
if not dynamic_parametrization:
|
|
154
|
+
raise ValueError('can not determine dynamic parametrization, because there are no dynamic parameters')
|
|
155
|
+
|
|
156
|
+
# sort attributes according their Parameter - using TopologicalSorter
|
|
157
|
+
graph = {attr: [param.name for param in config.get_parameters(of_type=Parameter).values()]
|
|
158
|
+
for attr, config in dynamic_parametrization.items()}
|
|
159
|
+
# also add all elements from static parameters
|
|
160
|
+
graph.update({param: [] for param in self._static_parameters})
|
|
161
|
+
|
|
162
|
+
ts = TopologicalSorter(graph)
|
|
163
|
+
resolvable_order_of_attribues = ts.static_order()
|
|
164
|
+
resolvable_dynamic_attribues = [attr for attr in resolvable_order_of_attribues
|
|
165
|
+
if attr in dynamic_parametrization.keys()]
|
|
166
|
+
|
|
167
|
+
def get_variations_for(
|
|
168
|
+
resolved_parameters: Dict[str, Any],
|
|
169
|
+
remaining_attributes: Iterable[str]
|
|
170
|
+
) -> List[Dict[str, Any]]:
|
|
171
|
+
result = []
|
|
172
|
+
remaining_attributes = list(remaining_attributes).copy()
|
|
173
|
+
attr = remaining_attributes.pop(0)
|
|
174
|
+
feature_access_selector = dynamic_parametrization[attr]
|
|
175
|
+
# get value for this attribute
|
|
176
|
+
attr_value_list = feature_access_selector.get_value(resolved_parameters)
|
|
177
|
+
if not isinstance(attr_value_list, Iterable):
|
|
178
|
+
raise TypeError(
|
|
179
|
+
f'feature parametrizing not possible, because `{feature_access_selector.device.__qualname__}'
|
|
180
|
+
f'.{feature_access_selector.device_property_name}.{feature_access_selector.feature_property_name}` '
|
|
181
|
+
f'does not return Iterable')
|
|
182
|
+
|
|
183
|
+
for cur_value in attr_value_list:
|
|
184
|
+
parameters_with_cur_attr_value = resolved_parameters.copy()
|
|
185
|
+
parameters_with_cur_attr_value[attr] = cur_value
|
|
186
|
+
if len(remaining_attributes) > 0:
|
|
187
|
+
result.extend(get_variations_for(parameters_with_cur_attr_value, remaining_attributes))
|
|
188
|
+
else:
|
|
189
|
+
result.append(parameters_with_cur_attr_value)
|
|
190
|
+
|
|
191
|
+
return result
|
|
192
|
+
|
|
193
|
+
resolved_parameters = self._static_parameters.copy()
|
|
194
|
+
|
|
195
|
+
all_full_parametrization = get_variations_for(resolved_parameters, resolvable_dynamic_attribues)
|
|
196
|
+
|
|
197
|
+
# get combined parametrization
|
|
198
|
+
result = []
|
|
199
|
+
for cur_full_parametrization in all_full_parametrization:
|
|
200
|
+
cur_parameter_set = OrderedDict()
|
|
201
|
+
for cur_arg in inspect.getfullargspec(self._base_testcase_callable).args:
|
|
202
|
+
# only if this is a parametrization value
|
|
203
|
+
if cur_arg in cur_full_parametrization:
|
|
204
|
+
cur_parameter_set[cur_arg] = cur_full_parametrization[cur_arg]
|
|
205
|
+
result.append(cur_parameter_set)
|
|
206
|
+
return result
|
|
207
|
+
|
|
208
|
+
def cleanup_empty_executor_branches(self, consider_discarded=False):
|
|
209
|
+
pass
|
|
@@ -5,9 +5,11 @@ import inspect
|
|
|
5
5
|
import logging
|
|
6
6
|
from _balder.device import Device
|
|
7
7
|
from _balder.connection import Connection
|
|
8
|
-
from _balder.
|
|
9
|
-
from _balder.
|
|
8
|
+
from _balder.fixture_execution_level import FixtureExecutionLevel
|
|
9
|
+
from _balder.testresult import ResultState, BranchBodyResult, ResultSummary
|
|
10
|
+
from _balder.executor.basic_executable_executor import BasicExecutableExecutor
|
|
10
11
|
from _balder.executor.testcase_executor import TestcaseExecutor
|
|
12
|
+
from _balder.executor.unresolved_parametrized_testcase_executor import UnresolvedParametrizedTestcaseExecutor
|
|
11
13
|
from _balder.previous_executor_mark import PreviousExecutorMark
|
|
12
14
|
from _balder.routing_path import RoutingPath
|
|
13
15
|
from _balder.unmapped_vdevice import UnmappedVDevice
|
|
@@ -26,10 +28,11 @@ if TYPE_CHECKING:
|
|
|
26
28
|
logger = logging.getLogger(__file__)
|
|
27
29
|
|
|
28
30
|
|
|
29
|
-
class VariationExecutor(
|
|
31
|
+
class VariationExecutor(BasicExecutableExecutor):
|
|
30
32
|
"""
|
|
31
33
|
A VariationExecutor only contains :meth:`TestcaseExecutor` children.
|
|
32
34
|
"""
|
|
35
|
+
fixture_execution_level = FixtureExecutionLevel.VARIATION
|
|
33
36
|
|
|
34
37
|
def __init__(self, device_mapping: Dict[Type[Device], Type[Device]], parent: ScenarioExecutor):
|
|
35
38
|
super().__init__()
|
|
@@ -107,7 +110,7 @@ class VariationExecutor(BasicExecutor):
|
|
|
107
110
|
return self._base_device_mapping
|
|
108
111
|
|
|
109
112
|
@property
|
|
110
|
-
def all_child_executors(self) -> List[TestcaseExecutor]:
|
|
113
|
+
def all_child_executors(self) -> List[TestcaseExecutor | UnresolvedParametrizedTestcaseExecutor]:
|
|
111
114
|
return self._testcase_executors
|
|
112
115
|
|
|
113
116
|
@property
|
|
@@ -150,10 +153,10 @@ class VariationExecutor(BasicExecutor):
|
|
|
150
153
|
self.determine_abs_variation_connections()
|
|
151
154
|
self.update_scenario_device_feature_instances()
|
|
152
155
|
self.update_active_vdevice_device_mappings_in_all_features()
|
|
153
|
-
self.update_inner_referenced_feature_instances()
|
|
154
156
|
self.exchange_unmapped_vdevice_references()
|
|
155
157
|
self.update_vdevice_referenced_feature_instances()
|
|
156
158
|
self.set_conn_dependent_methods()
|
|
159
|
+
self.resolve_possible_parametrization()
|
|
157
160
|
|
|
158
161
|
def _body_execution(self, show_discarded):
|
|
159
162
|
if show_discarded and not self.can_be_applied():
|
|
@@ -283,28 +286,29 @@ class VariationExecutor(BasicExecutor):
|
|
|
283
286
|
|
|
284
287
|
# ---------------------------------- METHODS -----------------------------------------------------------------------
|
|
285
288
|
|
|
286
|
-
def testsummary(self):
|
|
289
|
+
def testsummary(self) -> ResultSummary:
|
|
287
290
|
if self.can_be_applied():
|
|
288
291
|
return super().testsummary()
|
|
289
|
-
return
|
|
290
|
-
ResultState.NOT_RUN: 0,
|
|
291
|
-
ResultState.FAILURE: 0,
|
|
292
|
-
ResultState.ERROR: 0,
|
|
293
|
-
ResultState.SUCCESS: 0,
|
|
294
|
-
ResultState.SKIP: 0,
|
|
295
|
-
ResultState.COVERED_BY: 0
|
|
296
|
-
}
|
|
292
|
+
return ResultSummary()
|
|
297
293
|
|
|
298
294
|
def get_testcase_executors(self) -> List[TestcaseExecutor]:
|
|
299
295
|
"""returns all sub testcase executors that belongs to this variation-executor"""
|
|
300
|
-
|
|
296
|
+
result = []
|
|
297
|
+
for cur_executor in self._testcase_executors:
|
|
298
|
+
if (isinstance(cur_executor, UnresolvedParametrizedTestcaseExecutor) and
|
|
299
|
+
cur_executor.parametrization_has_been_resolved):
|
|
300
|
+
result += cur_executor.get_testcase_executors()
|
|
301
|
+
else:
|
|
302
|
+
result.append(cur_executor)
|
|
303
|
+
return result
|
|
301
304
|
|
|
302
|
-
def add_testcase_executor(self, testcase_executor: TestcaseExecutor):
|
|
305
|
+
def add_testcase_executor(self, testcase_executor: TestcaseExecutor | UnresolvedParametrizedTestcaseExecutor):
|
|
303
306
|
"""
|
|
304
307
|
This method adds a new TestcaseExecutor to the child element list of this object branch
|
|
305
308
|
"""
|
|
306
|
-
if not isinstance(testcase_executor, TestcaseExecutor):
|
|
307
|
-
raise TypeError("the given object `testcase_executor` must be of type type `TestcaseExecutor`"
|
|
309
|
+
if not isinstance(testcase_executor, (TestcaseExecutor, UnresolvedParametrizedTestcaseExecutor)):
|
|
310
|
+
raise TypeError("the given object `testcase_executor` must be of type type `TestcaseExecutor` or "
|
|
311
|
+
"`UnresolvedParametrizedTestcaseExecutor`")
|
|
308
312
|
if testcase_executor in self._testcase_executors:
|
|
309
313
|
raise ValueError("the given object `testcase_executor` already exists in child list")
|
|
310
314
|
self._testcase_executors.append(testcase_executor)
|
|
@@ -469,7 +473,7 @@ class VariationExecutor(BasicExecutor):
|
|
|
469
473
|
raise KeyError("the requested setup device exists more than one time in `base_device_mapping`")
|
|
470
474
|
return [cur_key for cur_key, cur_value in self.base_device_mapping.items() if cur_value == setup_device][0]
|
|
471
475
|
|
|
472
|
-
def get_executor_for_testcase(self, testcase: callable) ->
|
|
476
|
+
def get_executor_for_testcase(self, testcase: callable) -> TestcaseExecutor | None:
|
|
473
477
|
"""
|
|
474
478
|
This method searches for a TestcaseExecutor in the internal list for which the given testcase method is
|
|
475
479
|
contained in
|
|
@@ -570,34 +574,6 @@ class VariationExecutor(BasicExecutor):
|
|
|
570
574
|
for cur_feature, cur_original_mapping in cur_feature_mapping_dict.items():
|
|
571
575
|
cur_feature.active_vdevices = cur_original_mapping
|
|
572
576
|
|
|
573
|
-
def update_inner_referenced_feature_instances(self):
|
|
574
|
-
"""
|
|
575
|
-
This method ensures that all inner referenced feature instances of the used feature object, will be replaced
|
|
576
|
-
with the related feature instances of the device object itself.
|
|
577
|
-
|
|
578
|
-
.. note::
|
|
579
|
-
Note that this method expects that the true defined scenario features are already replaced with the real
|
|
580
|
-
setup features. So the method requires that the method `update_scenario_device_feature_instances()` was
|
|
581
|
-
called before.
|
|
582
|
-
"""
|
|
583
|
-
for scenario_device, _ in self._base_device_mapping.items():
|
|
584
|
-
# these features are subclasses of the real defined one (because they are already the replaced ones)
|
|
585
|
-
all_device_features = DeviceController.get_for(scenario_device).get_all_instantiated_feature_objects()
|
|
586
|
-
all_instantiated_feature_objs = [cur_feature for _, cur_feature in all_device_features.items()]
|
|
587
|
-
for _, cur_feature in all_device_features.items():
|
|
588
|
-
cur_feature_controller = FeatureController.get_for(cur_feature.__class__)
|
|
589
|
-
# now check the inner referenced features of this feature and check if that exists in the device
|
|
590
|
-
for cur_ref_feature_name, cur_ref_feature in \
|
|
591
|
-
cur_feature_controller.get_inner_referenced_features().items():
|
|
592
|
-
potential_candidates = [candidate_feature for candidate_feature in all_instantiated_feature_objs
|
|
593
|
-
if isinstance(candidate_feature, cur_ref_feature.__class__)]
|
|
594
|
-
if len(potential_candidates) != 1:
|
|
595
|
-
raise RuntimeError("found none or more than one potential replacing candidates")
|
|
596
|
-
replacing_candidate = potential_candidates[0]
|
|
597
|
-
# because `cur_feature` is only the object instance, the value will be overwritten only for this
|
|
598
|
-
# object
|
|
599
|
-
setattr(cur_feature, cur_ref_feature_name, replacing_candidate)
|
|
600
|
-
|
|
601
577
|
def exchange_unmapped_vdevice_references(self):
|
|
602
578
|
"""
|
|
603
579
|
This method exchanges all :class:`VDevice` references to an instance of :class:`UnmappedVDevice` if the
|
|
@@ -722,10 +698,7 @@ class VariationExecutor(BasicExecutor):
|
|
|
722
698
|
if cur_scenario_device not in abs_var_scenario_device_cnns.keys():
|
|
723
699
|
abs_var_scenario_device_cnns[cur_scenario_device] = {}
|
|
724
700
|
|
|
725
|
-
|
|
726
|
-
cur_to_device = cur_cnn.to_device
|
|
727
|
-
else:
|
|
728
|
-
cur_to_device = cur_cnn.from_device
|
|
701
|
+
cur_to_device, _ = cur_cnn.get_conn_partner_of(cur_scenario_device)
|
|
729
702
|
|
|
730
703
|
if cur_to_device not in abs_var_scenario_device_cnns[cur_scenario_device].keys():
|
|
731
704
|
abs_var_scenario_device_cnns[cur_scenario_device][cur_to_device] = []
|
|
@@ -915,3 +888,9 @@ class VariationExecutor(BasicExecutor):
|
|
|
915
888
|
(mapped_vdevice, absolute_feature_method_var_cnn, cur_method_variation)
|
|
916
889
|
|
|
917
890
|
cur_setup_feature_controller.set_active_method_variation(method_selection=method_var_selection)
|
|
891
|
+
|
|
892
|
+
def resolve_possible_parametrization(self):
|
|
893
|
+
"""resolves the parametrization if there are any :class:`UnresolvedParametrizedTestcaseExecutor` in the tree"""
|
|
894
|
+
for cur_child in self._testcase_executors:
|
|
895
|
+
if isinstance(cur_child, UnresolvedParametrizedTestcaseExecutor):
|
|
896
|
+
cur_child.resolve_dynamic_parametrization()
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import List
|
|
3
|
+
from enum import Enum
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class FixtureDefinitionScope(Enum):
|
|
7
|
+
"""
|
|
8
|
+
This enum describes the definition scope of a fixture. A definition scope is the position the fixture was defined.
|
|
9
|
+
If the fixture was defined within the balderglob.py file, it has the definition-scope `GLOB`. If it is defined
|
|
10
|
+
within a scenario or setup it has the equivalent SCENARIO or SETUP scope.
|
|
11
|
+
"""
|
|
12
|
+
GLOB = 'glob'
|
|
13
|
+
SETUP = 'setup'
|
|
14
|
+
SCENARIO = 'scenario'
|
|
15
|
+
|
|
16
|
+
@classmethod
|
|
17
|
+
def get_order(cls) -> List[FixtureDefinitionScope]:
|
|
18
|
+
"""returns the priority order of the fixture definition scope"""
|
|
19
|
+
return [cls.GLOB, cls.SETUP, cls.SCENARIO]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import List
|
|
3
|
+
from enum import Enum
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class FixtureExecutionLevel(Enum):
|
|
7
|
+
"""
|
|
8
|
+
This enum describes the fixture-execution-level of a fixture. It describes when the fixture should be executed. This
|
|
9
|
+
level will be set in the fixture decorator.
|
|
10
|
+
"""
|
|
11
|
+
SESSION = 'session'
|
|
12
|
+
SETUP = 'setup'
|
|
13
|
+
SCENARIO = 'scenario'
|
|
14
|
+
VARIATION = 'variation'
|
|
15
|
+
TESTCASE = 'testcase'
|
|
16
|
+
|
|
17
|
+
@classmethod
|
|
18
|
+
def get_order(cls) -> List[FixtureExecutionLevel]:
|
|
19
|
+
"""
|
|
20
|
+
returns the execution order of fixtures
|
|
21
|
+
"""
|
|
22
|
+
return [cls.SESSION, cls.SETUP, cls.SCENARIO, cls.VARIATION, cls.TESTCASE]
|