Setting validator targets during test execution
- Dominant language
- Python
- Stars
- 722
- Forks
- 237
- Avg merge
- 11h 31m
- Merged PRs (30d)
- 4
Description
My use-case is setting a power supply voltage to a target value, and then checking that the voltage has been successfully achieved within a given tolerance. The target value is only known at runtime and is not hardcoded in the hardware tests (it could be but I want to explore this option). I have come up with a couple of ways of implementing this and wanted to ask for some thoughts here.
An example use-case:
```python
# at this point the limits are unknown
@measures(Measurement('powersupply_a_min', validators=[InRange(???)]))
def test_powersupply_a_minimum(test):
# at this point the limits are available but there is no easy
# mechanism to specify them as a validator
target_voltage = get_target_voltage()
set_supply_a(target_voltage)
test.measurements.powersupply_a_min = measure_supply_a()
```
The following are methods of implementing this:
1. Accessing the internal `_measurements` dictionary of `Collection` and adding a new validator at during the test: `test.measurements._measurements['voltage'].with_validator(InRange(minimum=4.485, maximum=4.515))`
2. Adding a method to `Collection` that can add validators during the test.
3. Using a validator class with a hacked `__deepcopy__()` method and setting it as normal using the decorator and manipulating it as a module-scope variable.
Method 1 is obviously using the internals of `Collection` and so is not desirable but it demonstrates possible access. This gives rise to the idea of having measurements returning their value via `test.measurements.measurement_name` when the value has been set, and prior to that returning the `Measurement` object so that it can be manipulated (in this case its `with_validator()` method would be called.
Method 2 is simple and works (as here https://github.com/JamesMTSloan/openhtf/commit/b59a5fe33bcd5324cf4df0afaf92a2de9b79fb19) but I suppose it rather violates what you want `Collection` to do by introducing public methods to it.
Method 3 is a nasty hack demonstrated as follows to around the deep copying that OpenHTF does when setting up the execution threads:
```python
class RunTimeTarget(ValidatorBase):
def __init__(self):
self.target = None
def __call__(self, value):
if self.target is None:
raise Exception("Target has not yet been set for this validator.")
return self.target == value
def __deepcopy__(self, memodict={}):
return self
my_validator = RunTimeTarget()
@measures(Measurement('something', validators=[my_validator]))
def measure_something(test):
my_validator.target = 5
test.measurements.something = 5
```
I do like the syntax though of using the walrus operator to make your validator accessible within the test.
```python
@measures(Measurement('something', validators=[my_validator := RunTimeTarget()]))
```
For my own use-case I will probably make sure the targets are available when defining the tests but perhaps there are cases where this is not possible. Is this just a use-case that should always be discouraged as it is too dynamic for hardware testing?
Contributor guide
Assessment
This issue has not been assessed yet.