Main Content

Create Basic Parameterized Test

This example shows how to create a parameterized test to test the output of a function in terms of value, class, and size.

Create Function to Test

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

Create TestCarpet Test Class

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.

Define Test methods Block

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 Test methods Block with ParameterCombination Attribute

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

Run All Tests

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.

Run Tests with level Property Named 'small'

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'));

See Also

| |

Related Topics