Main Content

创建基本参数化测试

此示例说明如何创建一个参数化测试来基于值、类和大小测试函数输出。

创建要测试的函数

在您当前文件夹的 sierpinski.m 文件中创建一个函数。此函数返回一个表示 Sierpinski 地毯分形图像的矩阵。它采用分形级别和可选数据类型作为输入。

function carpet = sierpinski(levels,classname)
if nargin == 1
    classname = 'single';
end

msize = 3^levels;
carpet = ones(msize,classname);

cutCarpet(1,1,msize,levels) % Begin recursion

    function cutCarpet(x,y,s,cl)
        if cl
            ss = s/3; % Define subsize
            for lx = 0:2
                for ly = 0:2
                    if lx == 1 && ly == 1
                        % Remove center square
                        carpet(x+ss:x+2*ss-1,y+ss:y+2*ss-1) = 0;
                    else
                        % Recurse
                        cutCarpet(x+lx*ss,y+ly*ss,ss,cl-1)
                    end
                end
            end
        end
    end
end

创建 TestCarpet 测试类

在当前文件夹的一个文件中创建 TestCarpet 类来测试 sierpinski 函数。在 properties 代码块中定义具有 TestParameter 特性的用于参数化测试的属性。

classdef TestCarpet < matlab.unittest.TestCase   
    properties (TestParameter)
        type = {'single','double','uint16'};
        level = struct('small',2,'medium',4,'large',6);
        side = struct('small',9,'medium',81,'large',729);
    end
end

type 属性包含您要测试的不同数据类型。level 属性包含您要测试的不同分形级别。side 属性包含 Sierpinski 地毯矩阵的行数和列数并且对应于 level 属性。

定义测试方法块

在具有 Test 特性的 methods 代码块中,定义三个测试方法:

  • testRemainPixels 方法通过验证特定级别的非零像素数是否与预期相同,来测试 sierpinski 函数的输出。此方法使用 level 属性,因此产生三个测试元素 - level 中的每个值各一个。

  • testClass 方法使用 typelevel 参数值的每一个组合(即穷举参数组合)测试 sierpinski 函数的输出的类。该方法产生九个测试元素。

  • testDefaultL1Output 方法不使用 TestParameter 属性,因此不会被参数化。该方法验证 1 级矩阵是否包含预期值。因为该测试方法未参数化,所以只产生一个测试元素。

classdef TestCarpet < matlab.unittest.TestCase   
    properties (TestParameter)
        type = {'single','double','uint16'};
        level = struct('small',2,'medium',4,'large',6);
        side = struct('small',9,'medium',81,'large',729);
    end
    
    methods (Test)
        function testRemainPixels(testCase,level)
            expPixelCount = 8^level;
            actPixels = find(sierpinski(level));
            testCase.verifyNumElements(actPixels,expPixelCount)
        end
        
        function testClass(testCase,type,level)
            testCase.verifyClass( ...
                sierpinski(level,type),type)
        end
        
        function testDefaultL1Output(testCase)
            exp = single([1 1 1; 1 0 1; 1 1 1]);
            testCase.verifyEqual(sierpinski(1),exp)
        end
    end
end

使用 ParameterCombination 属性定义测试方法块

定义 testNumel 方法,以确保 sierpinski 函数返回的矩阵具有正确的元素数。将该方法的 ParameterCombination 特性设置为 'sequential'。由于 levelside 属性都指定三个参数值,testNumel 方法被调用三次,即分别针对 'small''medium''large' 值调用一次。

classdef TestCarpet < matlab.unittest.TestCase   
    properties (TestParameter)
        type = {'single','double','uint16'};
        level = struct('small',2,'medium',4,'large',6);
        side = struct('small',9,'medium',81,'large',729);
    end
    
    methods (Test)
        function testRemainPixels(testCase,level)
            expPixelCount = 8^level;
            actPixels = find(sierpinski(level));
            testCase.verifyNumElements(actPixels,expPixelCount)
        end
        
        function testClass(testCase,type,level)
            testCase.verifyClass( ...
                sierpinski(level,type),type)
        end
        
        function testDefaultL1Output(testCase)
            exp = single([1 1 1; 1 0 1; 1 1 1]);
            testCase.verifyEqual(sierpinski(1),exp)
        end
    end
    
    methods (Test, ParameterCombination = 'sequential')
        function testNumel(testCase,level,side)
            import matlab.unittest.constraints.HasElementCount
            testCase.verifyThat(sierpinski(level), ...
                HasElementCount(side^2))
        end
    end 
end

运行所有测试

在命令提示符下,基于 TestCarpet.m 创建一个套件。该套件有 16 个测试元素。MATLAB® 在套件元素的名称中包含参数化信息。

suite = matlab.unittest.TestSuite.fromFile('TestCarpet.m');
{suite.Name}'
ans =

  16×1 cell array

    {'TestCarpet/testNumel(level=small,side=small)'  }
    {'TestCarpet/testNumel(level=medium,side=medium)'}
    {'TestCarpet/testNumel(level=large,side=large)'  }
    {'TestCarpet/testRemainPixels(level=small)'      }
    {'TestCarpet/testRemainPixels(level=medium)'     }
    {'TestCarpet/testRemainPixels(level=large)'      }
    {'TestCarpet/testClass(type=single,level=small)' }
    {'TestCarpet/testClass(type=single,level=medium)'}
    {'TestCarpet/testClass(type=single,level=large)' }
    {'TestCarpet/testClass(type=double,level=small)' }
    {'TestCarpet/testClass(type=double,level=medium)'}
    {'TestCarpet/testClass(type=double,level=large)' }
    {'TestCarpet/testClass(type=uint16,level=small)' }
    {'TestCarpet/testClass(type=uint16,level=medium)'}
    {'TestCarpet/testClass(type=uint16,level=large)' }
    {'TestCarpet/testDefaultL1Output'                }

运行测试。

suite.run
Running TestCarpet
.......... ......
Done TestCarpet
__________


ans = 

  1×16 TestResult array with properties:

    Name
    Passed
    Failed
    Incomplete
    Duration
    Details

Totals:
   16 Passed, 0 Failed, 0 Incomplete.
   2.459 seconds testing time.

运行 level 属性命名为 'small' 的测试

使用 TestSuiteselectIf 方法选择使用特定参数化的测试元素。选择所有在 level 参数化属性列表中使用参数名称 'small' 的测试元素。过滤后的套件有五个元素。

s1 = suite.selectIf('ParameterName','small');
{s1.Name}'
ans =

  5×1 cell array

    {'TestCarpet/testNumel(level=small,side=small)' }
    {'TestCarpet/testRemainPixels(level=small)'     }
    {'TestCarpet/testClass(type=single,level=small)'}
    {'TestCarpet/testClass(type=double,level=small)'}
    {'TestCarpet/testClass(type=uint16,level=small)'}

运行过滤后的测试套件。

s1.run;
Running TestCarpet
.....
Done TestCarpet
__________

您也可以直接使用 TestSuitefromFile 方法创建相同的测试套件。

import matlab.unittest.selectors.HasParameter
s1 = matlab.unittest.TestSuite.fromFile('TestCarpet.m', ...
    HasParameter('Name','small'));

另请参阅

| |

相关主题