Main Content

데이터를 테스트 결과에 추가하는 플러그인 작성하기

이 예제에서는 데이터를 TestResult 객체에 추가하는 플러그인을 만드는 방법을 보여줍니다. 이 플러그인은 어설션에서 실제 값과 예상 값을 TestResult 객체의 Details 속성에 추가합니다. TestRunner를 확장하기 위해 플러그인은 matlab.unittest.plugins.TestRunnerPlugin 클래스의 선택 메서드를 재정의합니다.

플러그인 클래스 생성하기

현재 폴더의 파일에서, TestRunnerPlugin 클래스에서 상속되는 사용자 지정 플러그인 클래스 DetailsRecordingPlugin을 생성하십시오. DetailsRecordingPlugin에 대한 전체 코드를 보려면 DetailsRecordingPlugin 클래스 정의 요약을 참조하십시오.

TestResult 객체에 실제 값과 예상 값을 저장하려면 properties 블록 내에 두 상수 속성 ActFieldExpField를 정의하십시오. ActField의 값을 실제 값이 포함된 Details 구조체의 필드 이름으로 설정합니다. ExpField의 값을 예상 값이 포함된 필드 이름으로 설정합니다.

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

Details 속성에 필드 추가하기

테스트 세션에 속한 모든 TestResult 객체의 Details 속성에 새 필드를 추가하려면 protected 액세스 권한이 있는 methods 블록에서 TestRunnerPluginrunSession 메서드를 재정의하십시오. runSessionTestResult 객체의 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 구조체에 빈 필드가 추가됩니다.

공유 테스트 픽스처(Fixture)와 TestCase 인스턴스 생성 확장하기

테스트 콘텐츠를 생성하기 위해 테스트 프레임워크에서 사용하는 메서드를 확장하여 AssertionPassedAssertionFailed 이벤트에 대한 리스너를 추가합니다. 테스트 콘텐츠에는 각 Test 요소에 대한 TestCase 인스턴스, TestClassSetup 메서드 블록과 TestClassTeardown 메서드 블록에 대한 클래스 레벨 TestCase 인스턴스, TestCase 클래스에 SharedTestFixtures 특성(Attribute)이 있을 때 사용되는 Fixture 인스턴스가 포함됩니다.

생성(Creation) 메서드를 무시할 때는 상응하는 슈퍼클래스 메서드를 불러오십시오. 반환되는 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 제약 조건을 기반으로 어설션에서 실제 값과 예상 값을 추출하고, 예상 값을 셀형 배열로 변환하고, 셀형 배열을 대응하는 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

참고 항목

| | | | | |

관련 항목