Main Content

テスト結果にデータを追加するプラグインの作成

この例では、TestResult オブジェクトにデータを追加するプラグインの作成方法を説明します。このプラグインは、アサーション内の実際の値と期待値を、TestResult オブジェクトの Details プロパティに追加します。TestRunner を拡張するため、プラグインは matlab.unittest.plugins.TestRunnerPlugin クラスの特定メソッドをオーバーライドします。

プラグイン クラスの作成

現在のフォルダー内のファイルに、TestRunnerPlugin クラスから継承するカスタム プラグイン クラス DetailsRecordingPlugin を作成します。DetailsRecordingPlugin の完全なコードは、DetailsRecordingPlugin クラス定義の概要を参照してください。

実際の値と期待値を TestResult オブジェクトに保存するには、2 つの定数プロパティ ActField および ExpField を、properties ブロック内で定義します。ActField の値を、実際の値を含む Details 構造体のフィールド名に設定します。ExpField の値を、期待値を含むフィールドの名前に設定します。

    properties (Constant, Access = private)
        ActField = 'ActualValue';
        ExpField = 'ExpectedValue';
    end

Details プロパティへのフィールドの追加

テスト セッションに属するすべての TestResult オブジェクトの Details プロパティに新しいフィールドを追加するには、protected アクセスをもつ methods ブロック内にある TestRunnerPluginrunSession メソッドをオーバーライドします。runSession は、TestResult オブジェクトの Details 構造体に対して空のフィールドを 2 つ追加し、テスト実行全体をトリガーするスーパークラス メソッドを呼び出します。

    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

フィールドを追加するために、runSession の実装には、matlab.unittest.plugins.plugindata.ResultDetails クラスの append メソッドに対する呼び出しが含まれます。呼び出しごとに、空のフィールドが Details 構造体に追加されます。

共有テスト フィクスチャと TestCase インスタンスの作成の拡張

テスト フレームワークで使用するメソッドを拡張してテスト内容を作成することにより、AssertionPassed イベントおよび AssertionFailed イベントのリスナーを追加します。テスト内容には、Test 要素ごとの TestCase インスタンス、TestClassSetup および TestClassTeardown メソッド ブロックに対するクラス レベルの TestCase インスタンス、および TestCase クラスが属性 SharedTestFixtures をもつ場合に使用する Fixture インスタンスが含まれます。

作成メソッドをオーバーライドする際に、対応するスーパークラスを呼び出します。返される Fixture インスタンスまたは TestCase インスタンスに追加するリスナーにより、アサーションが実行されるたびに reactToAssertion 補助メソッドが実行されます。テスト結果にアサーション データを追加するには、結果修飾子インスタンスを、アサーション イベント リスナーのデータと共に、補助メソッドに渡します。

protected アクセスが指定された methods ブロックにこれらの作成メソッドを追加します。

    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

補助メソッドの定義

private アクセスが指定された methods ブロックで、補助メソッド reactToAssertion を定義します。このメソッドは、QualificationEventData インスタンスを使用してアサーション内の実際の値と期待値を IsEqualTo 制約に基づいて抽出し、抽出された値を cell 配列に変換し、その cell 配列を対応する TestResult オブジェクトのフィールドに追加します。

    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 クラス定義の概要

以下のコードは、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

サンプル テスト クラスの作成

現在のフォルダーに、以下のパラメーター化されたテスト クラスを含む ExampleTest.m という名前のファイルを作成します。クラスは結果的に 25 個の要素をもつテスト スイートとなり、各要素は、乱数発生器の別々のシードを使用して実行されたそれぞれの実験に対応します。各実験で、テスト フレームワークは、正規分布した乱数の 1 行 100 列のベクトルを作成し、実際のサンプル平均と期待されるサンプル平均の差の大きさが 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

TestRunner にプラグインを追加してテストを実行

コマンド プロンプトで ExampleTest クラスからテスト スイートを作成します。

import matlab.unittest.TestSuite
import matlab.unittest.TestRunner

suite = TestSuite.fromClass(?ExampleTest);

プラグインなしで TestRunner インスタンスを作成します。このコードはメッセージを表示しないランナーを作成し、インストールされたプラグインの制御を可能にします。

runner = TestRunner.withNoPlugins;

DetailsRecordingPlugin をランナーに追加して、テストを実行します。

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.

乱数発生の動作に関する詳細を取得するには、テスト結果の Details 構造体から構造体配列を作成します。

details = [result.Details]
details = 

  1×25 struct array with fields:

    ActualValue
    ExpectedValue

各テストでの実際の値と期待値の差を含む配列を作成し、誤差値を棒グラフで表示します。長さが 0.1 より大きい 7 本のバーは、失敗したテストに相当します。

errorInMean = cell2mat([details.ExpectedValue]) - cell2mat([details.ActualValue]);

bar(errorInMean)
xlabel('Experiment')
ylabel('Error')

Bar graph depicting error versus experiment

参考

| | | | | |

関連するトピック