Collect Code Coverage Metrics for MATLAB Source Code
When you run tests, you can collect and access code coverage information for your MATLAB® source code by adding an instance of the
matlab.unittest.plugins.CodeCoveragePlugin class to the test runner. The plugin supports several coverage types, including decision coverage, condition coverage, and modified condition/decision coverage (MC/DC). These coverage types let you perform a detailed analysis of the source code covered by the tests. For more information about coverage types, see Types of Code Coverage for MATLAB Source Code.
To perform a code coverage analysis using the supported coverage types, specify the
MetricLevel name-value argument when you create a plugin using one of the static methods of the
CodeCoveragePlugin class. The
MetricLevel argument specifies which coverage types to include in the analysis. This list shows the possible values of
MetricLevel and the included coverage types:
"statement"(default value) — Statement and function coverage
"decision"— Statement, function, and decision coverage
"condition"— Statement, function, decision, and condition coverage
"mcdc"— Statement, function, decision, condition, and modified condition/decision coverage
This example shows how to collect code coverage metrics and generate a report including all the supported coverage types for source code in a file. The file defines the
QuadraticPolynomial class, which represents quadratic polynomials. The class constructor first validates that the coefficients of the polynomial are numeric values and then uses these values to initialize the class properties. The class includes the
solve method to return the roots of the specified quadratic polynomial, and the
plot method to plot the polynomial around its axis of symmetry. To view the complete code for
QuadraticPolynomial Class Definition.
Collect and Analyze Code Coverage Information
In your current folder, save the
QuadraticPolynomial class definition in a file named
QuadraticPolynomial.m. Then, create the
QuadraticPolynomialTest test class in your current folder. The test class has four
realSolution— Test the
solvemethod against a real solution.
imaginarySolution— Test the
solvemethod against an imaginary solution.
nonnumericInput— Test the constructor method against a nonnumeric input.
plotPolynomial— Test the
plotmethod against a label.
classdef QuadraticPolynomialTest < matlab.unittest.TestCase methods (Test) function realSolution(testCase) p = QuadraticPolynomial(1,-3,2); actSolution = p.solve(); expSolution = [1 2]; testCase.verifyEqual(actSolution,expSolution) end function imaginarySolution(testCase) p = QuadraticPolynomial(1,2,10); actSolution = p.solve(); expSolution = [-1-3i -1+3i]; testCase.verifyEqual(actSolution,expSolution) end function nonnumericInput(testCase) testCase.verifyError(@()QuadraticPolynomial(1,"-3",2), ... "QuadraticPolynomial:InputMustBeNumeric") end function plotPolynomial(testCase) p = QuadraticPolynomial(1,-3,2); fig = figure; testCase.addTeardown(@close,fig) ax = axes(fig); p.plot(ax) actYLabelText = ax.YLabel.String; expYLabelText = '1.00x^2-3.00x+2.00'; testCase.verifyEqual(actYLabelText,expYLabelText) end end end
To run tests and perform a code coverage analysis, first create a test runner with a plugin that provides programmatic access to information on all possible coverage types for the source code in the file
import matlab.unittest.plugins.CodeCoveragePlugin import matlab.unittest.plugins.codecoverage.CoverageResult runner = testrunner("textoutput"); format = CoverageResult; plugin = CodeCoveragePlugin.forFile("QuadraticPolynomial.m", ... Producing=format,MetricLevel="mcdc"); addPlugin(runner,plugin)
Create a test suite from the
QuadraticPolynomialTest class and run the tests. All the tests pass.
suite = testsuite("QuadraticPolynomialTest"); run(runner,suite);
Running QuadraticPolynomialTest ...
. Done QuadraticPolynomialTest __________
After the test run, the
Result property of the
CoverageResult object holds the coverage result. You can use this result to programmatically access information about different coverage types. Additionally, you can generate a code coverage report from the result.
result = format.Result;
QuadraticPolynomial class definition file has a single decision composed of three conditions. Access the decision coverage summary from the coverage result. The returned vector indicates that both the decision outcomes in the source code were achieved by the tests.
decisionSummary = coverageSummary(result,"decision")
decisionSummary = 1×2 2 2
Access the condition coverage summary. The summary indicates that the condition coverage is 66.7% because the tests missed two of the six possible condition outcomes in the
QuadraticPolynomial class definition file.
conditionSummary = coverageSummary(result,"condition")
conditionSummary = 1×2 4 6
Generate Code Coverage Report
Generate an HTML code coverage report from the coverage result. The report displays information about the collected code coverage information and uses different colors to highlight the executed or missed outcomes.
You can interact with the code coverage report. For example, in the Overall Coverage Summary section, you can select a coverage type from the Currently viewing list to view detailed information about that coverage type. The report has three sections:
Overall Coverage Summary — This section displays the collected code coverage metrics for the source code.
Breakdown by Source — This section displays the coverage metrics for each file in the source code. The value selected from the Currently viewing list determines which coverage metrics are displayed.
Source Details — This section provides the analysis details for a file selected in the Breakdown by Source section. The value selected from the Currently viewing list determines the columns and code highlighting in the table.
For example, this figure shows the condition coverage view of the report. The Source Details section indicates that only the second condition in the source file was evaluated to both
false. You can refer to the
Condition column to learn how the tests evaluated each condition. For instance,
T: 4, 3, 3 shows that the tests evaluated the conditions to
true for the specified number of times. On the other hand,
F: 0, 1, 0 shows that the second condition was evaluated to
false a single time whereas the other two conditions were not evaluated to
false. Out of six possible condition outcomes (that is,
false for each of the three conditions), the tests achieved only four outcomes.
Now, access the MC/DC view of the report by selecting
MC/DC from the Currently viewing list. MC/DC identifies how tests independently exercise conditions within decisions. A condition receives MC/DC if tests can:
Evaluate the condition to both
Verify that the condition can independently affect the outcome of the decision it belongs to.
To examine these requirements, the testing framework finds the combinations of condition outcomes that tests must achieve for each condition. For example, this figure shows the Source Details section for the MC/DC type. The
MC/DC column provides a pair of combinations for each condition, where
false, and don't-care values, respectively. Achieving both combinations for a condition ensures that the condition evaluates to both
false and that it independently affects the outcome of the decision:
For the first condition to receive MC/DC, tests must achieve the
For the second condition to receive MC/DC, tests must achieve the
For the third condition to receive MC/DC, tests must achieve the
Out of the
FFT combinations, the tests achieved only the
FTx combinations. Therefore, only the second condition satisfied the MC/DC requirements.
QuadraticPolynomial Class Definition
This code provides the complete contents of the
classdef QuadraticPolynomial properties A,B,C % Coefficients of a*x^2 + b*x + c end methods function obj = QuadraticPolynomial(a,b,c) if ~isa(a,"numeric") || ~isa(b,"numeric") || ~isa(c,"numeric") error("QuadraticPolynomial:InputMustBeNumeric", ... "Coefficients must be numeric.") else obj.A = a; obj.B = b; obj.C = c; end end function roots = solve(obj) % Return solutions to a*x^2 + b*x + c = 0 delta = calculateDelta(obj); roots(1) = (-obj.B - sqrt(delta)) / (2*obj.A); roots(2) = (-obj.B + sqrt(delta)) / (2*obj.A); end function plot(obj,ax) % Plot a*x^2 + b*x + c around its axis of symmetry delta = calculateDelta(obj); x0 = -obj.B/(2*obj.A); x1 = abs(sqrt(delta))/obj.A; x = x0 + linspace(-x1,x1); y = obj.A*x.^2 + obj.B*x + obj.C; plot(ax,x,y) xlabel("x") ylabel(sprintf("%.2fx^2%+.2fx%+.2f",obj.A,obj.B,obj.C)) end end methods (Access=private) function delta = calculateDelta(obj) delta = obj.B^2 - 4*obj.A*obj.C; end end end