在数组比较中允许给定数量的失败

时间:2016-12-09 17:59:23

标签: matlab unit-testing

我已经创建了一些单元测试,我生成一些时间序列数据并运行两个不同的估计,使用生成的数据大致相等。当我直观地检查结果时,看起来大多数数据点都能正常工作但有一些较大的错误。

现在,我使用verifyEqual进行比较设置以测试它们是否匹配。为了解决这个问题,我必须将verifyEqual的容差增加到比我认为合理的更大。我想设置一个测试,我检查数组中95%以上的元素是否满足给定的容差。

例如,以下测试失败:

array1 = (1:100)';
array2 = array1 + rand(100, 1) ./ 100 + [zeros(4,1); .5; zeros(95,1)];

testCase = matlab.unittest.TestCase.forInteractiveUse;
testCase.verifyEqual(array1, array2, 'AbsTol', 0.01)

在这种情况下,我很好,有一个元素超出了容忍度,但是如果超过5个元素失败,我会担心。

是否有更好的方法在Matlab单元测试框架内运行此测试而不是testCase.verifyLessThanOrEqual(sum(abs(array1 - array2) >= 0.01), 5),即提供信息性故障输出的方法?

1 个答案:

答案 0 :(得分:2)

目前测试框架中没有公差来提供此功能,但我认为它是一个有趣且好的用例。我将创建一个增强请求以提供这样的容差。

然而,与此同时,您可以创建自己的容差来执行此操作。 Here是描述如何执行此操作的文档。基本上它涉及编写supports方法,该方法传递一个值并确定容差是否可以应用于该值。然后,您需要实现一个satisfiedBy方法,该方法将两个值进行比较并确定它们是否在容差范围内。最后,您需要实现一个getDiagnosticFor方法来返回一个诊断,为您提供所有信息输出。这里有一些东西可以帮助你入门:

classdef ForgivingAbsoluteTolerance < matlab.unittest.constraints.Tolerance

    properties
        % QualityRequired - percent of the compared array that needs to be
        % within the specified tolerance
        QualityRequired = 0.95; 
        AbsTolValue;
    end

    methods
        function tolerance = ForgivingAbsoluteTolerance(absTol, quality)
            tolerance.AbsTolValue = absTol;
            if nargin > 1
                tolerance.QualityRequired = quality;
            end
        end

        function tf = supports(~, value)
            tf = isnumeric(value);
        end

        function tf = satisfiedBy(tolerance, actual, expected)
            withinTolerance = findWithinTolerance(actual, expected, tolerance.AbsTolValue);
            tf = nnz(withinTolerance) >= numel(expected)*tolerance.QualityRequired;
        end


        function diag = getDiagnosticFor(tolerance, actual, expected)
            import matlab.unittest.diagnostics.StringDiagnostic;

            withinTolerance = findWithinTolerance(actual, expected, tolerance.AbsTolValue);
            numValuesOutsideTolerance = nnz(~withinTolerance);
            str = [...
                num2str(numValuesOutsideTolerance) ' values were found outside of the tolerance value of ' num2str(tolerance.AbsTolValue), newline, ...
                'The tolerance''s quality of ' num2str(tolerance.QualityRequired) ' allows ' num2str(floor(numel(expected)*(1-tolerance.QualityRequired))) ' elements to be outside of the tolerance.', newline, ...
                '    Failing Indices: ' mat2str(find(~withinTolerance))];
            diag = StringDiagnostic(str);
        end
    end
end

function mask = findWithinTolerance(actual,expected, tolerance)
mask = abs(expected - actual) <= tolerance;
mask = mask(:).'; % make a row for better mat2str output
end

这只是一个开始。通过更多的时间/精力,您可以更好地进行诊断。但是,一旦你写了这个,你可以通过发出以下调用来重复使用它:

testCase.verifyThat(array1, IsEqualTo(array2, 'Within', ));


>> array1 = (1:100)';
>> array2 = array1 + rand(100, 1) ./ 100 + [zeros(4,1); .5; zeros(95,1)];

>> testCase = matlab.unittest.TestCase.forInteractiveUse;
>> testCase.verifyThat(array1, IsEqualTo(array2, 'Within', ForgivingAbsoluteTolerance(0.01)))
Interactive verification passed.

>> % now let's see a failing one.
>> array2 = array1 + rand(100, 1) ./ 100 + [zeros(4,1); ones(6,1)*.5; zeros(90,1)];
>> testCase.verifyThat(array1, IsEqualTo(array2, 'Within', ForgivingAbsoluteTolerance(0.01)))
Interactive verification failed.

---------------------
Framework Diagnostic:
---------------------
IsEqualTo failed.
--> NumericComparator failed.
    --> The values are not equal using "isequaln".
    --> 6 values were found outside of the tolerance value of 0.01
        The tolerance's quality of 0.95 allows 5 elements to be outside of the tolerance.
            Failing Indices: [5 6 7 8 9 10]

    Actual double:
        100x1 double
    Expected double:
        100x1 double
>>