How to write a composite contraint or comparator to be usable in unittest framework
조회 수: 3(최근 30일)
I'm struggeling with a supposedly simple task:
For a given example class
some_string (1,1) string = "some_string"
some_vague_number (1,1) double = 0
some_precise_number (1,1) double = pi()
I want to write a constraint that checks "similarity" of two instances of the class. The strings should be equal and I want to parametrize the tolerances for each property separately. Clearly i could verify the conditions one after another but I would have to repeat that for each qualification, which is not good, when the class changes.
In short, I would like to have a class that combines a sequence of Comparators (pluggable into IsEqualTo(...'Using'...) ) or a constraint that uses the tolerances for checking and the diagnostic reporting thereof.
I have already made some attempts that don't work:
- Derive a class SimpleClassComparator from IsEqualTo and pass an array of PublicPropertyComparator, each just looking at one field, to the base class constructor. But the the tests always pass.
- Derive a class from contraint and implement the abstract methods as a sequence of my nested constraints for each field. That had some other problems and cannot be used for containers.
I can provide code for my approaches but firstly I would like to know:
What is the right way to implement a custom Comparator for the unittest framework?
Lawrence 2021년 3월 16일
편집: Lawrence 2021년 3월 17일
A bit of a late reply, but here's a solution for anyone still needing one.
Probably implementing a custom constraint is simpler than implementing a custom comparator. You would follow the steps here: https://www.mathworks.com/help/matlab/matlab_prog/create-custom-constraint.html. I'm not sure what you mean by "That had some other problems and cannot be used for containers", but the code below works with the SimpleClass you provided.
In short, the constructor of the constraint would take an expected value and two additional tolerance inputs, all of which are stored to member variables. Then you would have a helper function to do the comparisons.
classdef similarTo < matlab.unittest.constraints.Constraint
properties (SetAccess = immutable)
function constraint = similarTo(expected,large_tolerance,small_tolerance)
constraint.expected = expected;
constraint.large_tolerance = large_tolerance;
constraint.small_tolerance = small_tolerance;
function bool = satisfiedBy(constraint,actual)
bool = constraint.customSimilarTo(actual);
function diag = getDiagnosticFor(constraint,actual)
diag = StringDiagnostic('similarTo has passed.');
diag = StringDiagnostic(sprintf(['similarTo has failed.\n'...
'Actual string: %s, Expected string: %s\n'...
'Actual vagueNum: %d, Expected vagueNum: %d, Precision: %d\n'...
'Actual preciseNum: %d, Expected preciseNum: %d, Precision: %d'],...
actual.some_vague_number, constraint.expected.some_vague_number, constraint.large_tolerance...
actual.some_precise_number, constraint.expected.some_precise_number, constraint.small_tolerance));
methods (Access = private)
function bool = customSimilarTo(constraint, actual)
bool = strcmp(actual.some_string, expected.some_string)...
&& abs(actual.some_vague_number - constraint.expected.some_vague_number) < constraint.large_tolerance...
&& abs(actual.some_precise_number - constraint.expected.some_precise_number) < constraint.small_tolerance;
You then use this in your unit test:
verifyThat(testCase, actual, similarTo(expected, large_tolerance, small_tolerance))
Some customizations you could do would be baking the tolerances into the constraint class, either within similarTo or by sub-classing from it, and splitting the conditions in customSimilarTo into separate helper functions, so you can have a more granular diagnostic in getDiagnosticFor.
If by "cannot be used for containers" you are talking about arrays and cell arrays, you can combine the custom similarTo constraint with matlab's EveryElementOf and EveryCellOf without any additional modification.