Write Plugin to Add Data to Test Results
This example shows how to create a plugin that adds data to
TestResult
objects. The plugin appends the actual and
expected values in an assertion to the Details
property of the
TestResult
object. To extend the
TestRunner
, the plugin overrides select methods of the
matlab.unittest.plugins.TestRunnerPlugin
class.
Create Plugin Class
In a file in your current folder, create the custom plugin class
DetailsRecordingPlugin
, which inherits from the
TestRunnerPlugin
class. For the complete code for
DetailsRecordingPlugin
, see DetailsRecordingPlugin Class Definition Summary.
To store the actual and expected values in TestResult
objects, define two constant properties, ActField
and
ExpField
, within a properties
block.
Set the value of ActField
to the name of the field of the
Details
structure that contains the actual value. Set the
value of ExpField
to the name of the field that contains the
expected value.
properties (Constant, Access = private) ActField = 'ActualValue'; ExpField = 'ExpectedValue'; end
Add Fields to Details Property
To add new fields to the Details
property of all
TestResult
objects belonging to the test session,
override the runSession
method of
TestRunnerPlugin
in a methods
block
with protected
access. runSession
adds two
empty fields to the Details
structure of
TestResult
objects and invokes the superclass method to
trigger the entire test run.
methods (Access = protected) function runSession(plugin,pluginData) resultDetails = pluginData.ResultDetails; resultDetails.append(plugin.ActField,{}) resultDetails.append(plugin.ExpField,{}) runSession@matlab.unittest.plugins.TestRunnerPlugin(plugin,pluginData); end end
To add the fields, the implementation of runSession
contains calls to the append
method of the
matlab.unittest.plugins.plugindata.ResultDetails
class.
Each call adds an empty field to the Details
structure.
Extend Creation of Shared Test Fixtures and TestCase Instances
Add listeners for the AssertionPassed
and
AssertionFailed
events by extending the methods used by
the testing framework to create the test content. The test content includes
TestCase
instances for each Test
element, class-level TestCase
instances for the
TestClassSetup
and TestClassTeardown
method blocks, and Fixture
instances used when a
TestCase
class has the
SharedTestFixtures
attribute.
Invoke the corresponding superclass method when you override the creation
methods. The listeners that you add to the returned Fixture
or TestCase
instances cause the
reactToAssertion
helper
method to execute whenever an assertion is performed. To add
assertion data to test results, pass the result modifier instance along with the
assertion event listener data to the helper method.
Add these creation methods to a methods
block with
protected
access.
methods (Access = protected) function fixture = createSharedTestFixture(plugin, pluginData) fixture = createSharedTestFixture@... matlab.unittest.plugins.TestRunnerPlugin(plugin, pluginData); resultDetails = pluginData.ResultDetails; fixture.addlistener('AssertionPassed',... @(~,evd)plugin.reactToAssertion(evd,resultDetails)); fixture.addlistener('AssertionFailed',... @(~,evd)plugin.reactToAssertion(evd,resultDetails)); end function testCase = createTestClassInstance(plugin,pluginData) testCase = createTestClassInstance@... matlab.unittest.plugins.TestRunnerPlugin(plugin,pluginData); resultDetails = pluginData.ResultDetails; testCase.addlistener('AssertionPassed',... @(~,evd)plugin.reactToAssertion(evd,resultDetails)); testCase.addlistener('AssertionFailed',... @(~,evd)plugin.reactToAssertion(evd,resultDetails)); end function testCase = createTestMethodInstance(plugin,pluginData) testCase = createTestMethodInstance@... matlab.unittest.plugins.TestRunnerPlugin(plugin,pluginData); resultDetails = pluginData.ResultDetails; testCase.addlistener('AssertionPassed',... @(~,evd)plugin.reactToAssertion(evd,resultDetails)); testCase.addlistener('AssertionFailed',... @(~,evd)plugin.reactToAssertion(evd,resultDetails)); end end
Define Helper Method
In a methods
block with private
access,
define the helper method reactToAssertion
. This method uses
the QualificationEventData
instance to
extract the actual and expected values in assertions based on the IsEqualTo
constraint, converts the
extracted values to cell arrays, and appends the cell arrays to the fields of
the corresponding TestResult
object.
methods (Access = private) function reactToAssertion(plugin,evd,resultDetails) if ~isa(evd.Constraint,'matlab.unittest.constraints.IsEqualTo') return end resultDetails.append(plugin.ActField,{evd.ActualValue}) resultDetails.append(plugin.ExpField,{evd.Constraint.Expected}) end end
DetailsRecordingPlugin Class Definition Summary
This code provides the complete contents of
DetailsRecordingPlugin
.
classdef DetailsRecordingPlugin < matlab.unittest.plugins.TestRunnerPlugin properties (Constant, Access = private) ActField = 'ActualValue'; ExpField = 'ExpectedValue'; end methods (Access = protected) function runSession(plugin,pluginData) resultDetails = pluginData.ResultDetails; resultDetails.append(plugin.ActField,{}) resultDetails.append(plugin.ExpField,{}) runSession@matlab.unittest.plugins.TestRunnerPlugin(plugin,pluginData); end function fixture = createSharedTestFixture(plugin, pluginData) fixture = createSharedTestFixture@... matlab.unittest.plugins.TestRunnerPlugin(plugin, pluginData); resultDetails = pluginData.ResultDetails; fixture.addlistener('AssertionPassed',... @(~,evd)plugin.reactToAssertion(evd,resultDetails)); fixture.addlistener('AssertionFailed',... @(~,evd)plugin.reactToAssertion(evd,resultDetails)); end function testCase = createTestClassInstance(plugin,pluginData) testCase = createTestClassInstance@... matlab.unittest.plugins.TestRunnerPlugin(plugin,pluginData); resultDetails = pluginData.ResultDetails; testCase.addlistener('AssertionPassed',... @(~,evd)plugin.reactToAssertion(evd,resultDetails)); testCase.addlistener('AssertionFailed',... @(~,evd)plugin.reactToAssertion(evd,resultDetails)); end function testCase = createTestMethodInstance(plugin,pluginData) testCase = createTestMethodInstance@... matlab.unittest.plugins.TestRunnerPlugin(plugin,pluginData); resultDetails = pluginData.ResultDetails; testCase.addlistener('AssertionPassed',... @(~,evd)plugin.reactToAssertion(evd,resultDetails)); testCase.addlistener('AssertionFailed',... @(~,evd)plugin.reactToAssertion(evd,resultDetails)); end end methods (Access = private) function reactToAssertion(plugin,evd,resultDetails) if ~isa(evd.Constraint,'matlab.unittest.constraints.IsEqualTo') return end resultDetails.append(plugin.ActField,{evd.ActualValue}) resultDetails.append(plugin.ExpField,{evd.Constraint.Expected}) end end end
Create Example Test Class
In your current folder, create a file named ExampleTest.m
containing the following parameterized test class. The class results in a test
suite with 25 elements, each corresponding to an experiment performed using a
different seed for the random number generator. In each experiment, the testing
framework creates a 1-by-100 vector of normally distributed random numbers and
asserts that the magnitude of the difference between the actual and expected
sample means is within 0.1.
classdef ExampleTest < matlab.unittest.TestCase properties SampleSize = 100; end properties (TestParameter) seed = num2cell(randi(10^6,1,25)); end methods(Test) function testMean(testCase,seed) import matlab.unittest.constraints.IsEqualTo import matlab.unittest.constraints.AbsoluteTolerance rng(seed) testCase.assertThat(mean(randn(1,testCase.SampleSize)),... IsEqualTo(0,'Within',AbsoluteTolerance(0.1))); end end end
Add Plugin to TestRunner and Run Tests
At the command prompt, create a test suite from the
ExampleTest
class.
import matlab.unittest.TestSuite import matlab.unittest.TestRunner suite = TestSuite.fromClass(?ExampleTest);
Create a TestRunner
instance with no plugins. This code
creates a silent runner and gives you control over the installed plugins.
runner = TestRunner.withNoPlugins;
Add DetailsRecordingPlugin
to the runner and run the
tests.
runner.addPlugin(DetailsRecordingPlugin) result = runner.run(suite)
result = 1×25 TestResult array with properties: Name Passed Failed Incomplete Duration Details Totals: 18 Passed, 7 Failed (rerun), 7 Incomplete. 0.12529 seconds testing time.
To retrieve more information about the behavior of random number generation,
create a structure array from the Details
structures of the
test results.
details = [result.Details]
details = 1×25 struct array with fields: ActualValue ExpectedValue
Create an array containing the difference between the actual and expected values in each test and then display the error values in a bar graph. The seven bars with a length greater than 0.1 correspond to the failed tests.
errorInMean = cell2mat([details.ExpectedValue]) - cell2mat([details.ActualValue]); bar(errorInMean) xlabel('Experiment') ylabel('Error')
See Also
matlab.unittest.plugins.TestRunnerPlugin
| matlab.unittest.TestRunner
| matlab.unittest.fixtures.Fixture
| matlab.unittest.TestSuite
| addlistener
| matlab.unittest.TestResult
| matlab.unittest.plugins.plugindata.ResultDetails