创建基本参数化测试
此示例说明如何创建一个参数化测试来基于值、类和大小测试函数输出。
创建要测试的函数
在您当前文件夹的 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方法使用type和level参数值的每一个组合(即穷举参数组合)测试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'。由于 level 和 side 属性都指定三个参数值,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' 的测试
使用 TestSuite 的 selectIf 方法选择使用特定参数化的测试元素。选择所有在 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 __________
您也可以直接使用 TestSuite 的 fromFile 方法创建相同的测试套件。
import matlab.unittest.selectors.HasParameter s1 = matlab.unittest.TestSuite.fromFile('TestCarpet.m', ... HasParameter('Name','small'));
另请参阅
matlab.unittest.TestCase | matlab.unittest.selectors.HasParameter | matlab.unittest.TestSuite