This example shows how to create a parameterized test to test the output of a function in terms of value, class, and size.
In your current folder, create a function in the file
sierpinski.m
. This function returns a matrix representing
an image of a Sierpinski carpet fractal. It takes as input the fractal level and
an optional data type.
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
In a file in your current folder, create the TestCarpet
class to test the sierpinski
function. Define the properties
used for parameterized testing in a properties
block with the
TestParameter
attribute.
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
The type
property contains the different data types you
want to test. The level
property contains the different
fractal levels you want to test. The side
property contains
the number of rows and columns in the Sierpinski carpet matrix and corresponds
to the level
property. To provide meaningful names for each
parameter, level
and side
are defined as
structures.
In a methods
block with the Test
attribute, define three test methods:
The testRemainPixels
method tests the output of
the sierpinski
function by verifying that the
number of nonzero pixels is the same as expected for a particular
level. This method uses the level
property and,
therefore, results in three test elements—one for each value
in level
.
The testClass
method tests the class of the
output from the sierpinski
function with each
combination of the type
and
level
parameter values (that is, exhaustive
parameter combination). The method results in nine test
elements.
The testDefaultL1Output
method does not use a
TestParameter
property and, therefore, is not
parameterized. The method verifies that the level 1 matrix contains
the expected values. Because the test method is not parameterized,
it results in one test element.
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
Define the testNumel
method to ensure that the matrix
returned by the sierpinski
function has the correct number of
elements. Set the ParameterCombination
attribute for the
method to 'sequential'
. Because the level
and side
properties each specify three parameter values, the
testNumel
method is invoked three times — one time
for each of the 'small'
, 'medium'
, and
'large'
values.
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
At the command prompt, create a suite from TestCarpet.m
.
The suite has 16 test elements. MATLAB® includes parameterization information in the names of the suite
elements.
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' }
Run the tests.
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.
Use the selectIf
method of
TestSuite
to select test elements that use a particular
parameterization. Select all test elements that use the parameter name
'small'
in the level
parameterization
property list. The filtered suite has five elements.
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)'}
Run the filtered test suite.
s1.run;
Running TestCarpet ..... Done TestCarpet __________
Alternatively, you can create the same test suite directly using the
fromFile
method of TestSuite
.
import matlab.unittest.selectors.HasParameter s1 = matlab.unittest.TestSuite.fromFile('TestCarpet.m', ... HasParameter('Name','small'));
matlab.unittest.selectors.HasParameter
| matlab.unittest.TestCase
| matlab.unittest.TestSuite