Main Content

이 번역 페이지는 최신 내용을 담고 있지 않습니다. 최신 내용을 영문으로 보려면 여기를 클릭하십시오.

사용자 지정 플러그인을 사용해 병렬로 테스트 실행하기

이 예제에서는 테스트 병렬 실행을 지원하는 사용자 지정 플러그인을 만드는 방법을 보여줍니다. 사용자 지정 플러그인은 테스트 스위트에 대한 통과 어설션과 실패 어설션의 개수를 셉니다. TestRunner를 확장하기 위해 플러그인은 matlab.unittest.plugins.TestRunnerPlugin 클래스의 선택 메서드를 재정의합니다. 또한 테스트 병렬 실행을 지원하기 위해 플러그인은 matlab.unittest.plugins.Parallelizable 인터페이스를 서브클래스화합니다. 테스트를 병렬로 실행하려면 Parallel Computing Toolbox™가 필요합니다.

플러그인 클래스 생성하기

현재 폴더의 파일에서, TestRunnerPlugin 클래스와 Parallelizable 클래스 모두에서 상속되는 병렬화 가능 플러그인 클래스 AssertionCountingPlugin을 생성하십시오. AssertionCountingPlugin에 대한 전체 코드를 보려면 플러그인 클래스 정의 요약 항목을 참조하십시오.

통과 어설션 및 실패 어설션의 개수를 추적하려면 properties 블록 내에서 4개의 읽기 전용 속성을 정의하십시오. 현재 병렬 풀에 있는 각 MATLAB® 워커는 TestSuite 배열의 일부를 실행할 때 NumPassingAssertionsNumFailingAssertions를 사용하여 통과 어설션 및 실패 어설션의 개수를 추적합니다. MATLAB 클라이언트는 FinalizedNumPassingAssertionsFinalizedNumFailingAssertions를 사용하여 여러 워커에서 결과를 집계하고 테스트 세션 종료 시 통과 어설션과 실패 어설션의 총 개수를 보고합니다.

    properties (SetAccess = private)
        NumPassingAssertions
        NumFailingAssertions
        FinalizedNumPassingAssertions
        FinalizedNumFailingAssertions
    end

테스트 세션 실행 확장하기

전체 TestSuite 배열의 실행을 확장하려면 protected 액세스 권한이 있는 methods 블록에서 TestRunnerPluginrunSession 메서드를 재정의하십시오. 테스트 프레임워크는 클라이언트에서 이 메서드를 한 번 실행합니다.

    methods (Access = protected)
        function runSession(plugin, pluginData)
            suiteSize = numel(pluginData.TestSuite);
            fprintf('## Running a total of %d tests\n\n', suiteSize);
            plugin.FinalizedNumPassingAssertions = 0;
            plugin.FinalizedNumFailingAssertions = 0;

            runSession@matlab.unittest.plugins.TestRunnerPlugin(plugin, pluginData);

            fprintf('## Done running tests\n')
            plugin.printAssertionSummary()
        end
    end

runSession는 총 Test 요소 개수에 대한 정보를 표시하고, 텍스트 출력을 생성하기 위해 플러그인에서 사용하는 속성을 초기화하고, 전체 테스트 실행을 트리거하는 슈퍼클래스 메서드를 불러옵니다. 프레임워크가 슈퍼클래스 메서드 실행을 완료한 후에는 runSession이 헬퍼 메서드 printAssertionSummary를 호출하여 어설션 개수 요약을 표시합니다. (헬퍼 메서드 정의하기 항목을 참조하십시오.)

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

어설션을 셀 수 있도록 AssertionPassed 이벤트와 AssertionFailed 이벤트에 리스너를 추가하십시오. 이러한 리스너를 추가하려면 테스트 콘텐츠를 생성하기 위해 테스트 프레임워크에서 사용하는 메서드를 확장하십시오. 테스트 콘텐츠에는 각 Test 요소에 대한 TestCase 인스턴스, TestClassSetup 메서드 블록과 TestClassTeardown 메서드 블록에 대한 클래스 레벨 TestCase 인스턴스, TestCase 클래스에 SharedTestFixtures 특성(Attribute)이 있을 때 사용되는 Fixture 인스턴스가 포함됩니다.

생성(Creation) 메서드를 무시할 때는 상응하는 슈퍼클래스 메서드를 불러오십시오. 생성 메서드는 테스트 프레임워크가 각각의 맥락에 맞춰 생성하는 콘텐츠를 반환합니다. incrementPassingAssertionsCount 헬퍼 메서드와 incrementFailingAssertionsCount 헬퍼 메서드를 사용하여 이러한 메서드 중 하나를 구현할 때는 플러그인에 요구되는 리스너를 반환된 Fixture 인스턴스 또는 TestCase 인스턴스에 추가하십시오.

protected 액세스 권한이 있는 methods 블록에 이 생성 메서드를 추가하십시오.

    methods (Access = protected)
        function fixture = createSharedTestFixture(plugin, pluginData)
            fixture = createSharedTestFixture@...
                matlab.unittest.plugins.TestRunnerPlugin(plugin, pluginData);

            fixture.addlistener('AssertionPassed', ...
                @(~,~)plugin.incrementPassingAssertionsCount);
            fixture.addlistener('AssertionFailed', ...
                @(~,~)plugin.incrementFailingAssertionsCount);
        end

        function testCase = createTestClassInstance(plugin, pluginData)
            testCase = createTestClassInstance@...
                matlab.unittest.plugins.TestRunnerPlugin(plugin, pluginData);

            testCase.addlistener('AssertionPassed', ...
                @(~,~)plugin.incrementPassingAssertionsCount);
            testCase.addlistener('AssertionFailed', ...
                @(~,~)plugin.incrementFailingAssertionsCount);
        end

        function testCase = createTestMethodInstance(plugin, pluginData)
            testCase = createTestMethodInstance@...
                matlab.unittest.plugins.TestRunnerPlugin(plugin, pluginData);

            testCase.addlistener('AssertionPassed', ...
                @(~,~)plugin.incrementPassingAssertionsCount);
            testCase.addlistener('AssertionFailed', ...
                @(~,~)plugin.incrementFailingAssertionsCount);
        end
    end

테스트 스위트 일부의 실행 확장하기

테스트 프레임워크는 전체 TestSuite 배열을 여러 그룹으로 나누고 처리를 위해 이 그룹들을 워커에 할당합니다. 각 워커는 테스트 스위트 일부를 하나 이상 실행할 수 있습니다. 워커의 동작을 사용자 지정하려면 protected 액세스 권한이 있는 methods 블록에서 TestRunnerPluginrunTestSuite 메서드를 재정의하십시오.

TestRunner를 확장하여 워커가 실행하는 각 테스트 그룹의 식별자를 그룹 내 Test 요소 개수와 함께 표시하십시오. 또한 클라이언트가 이러한 값을 가져와 최종 결과를 생성할 수 있도록 통과 어설션 개수와 실패 어설션 개수를 버퍼에 저장하십시오. 모든 플러그인 메서드처럼 runTestSuite 메서드에서는 적합한 지점에서 상응하는 슈퍼클래스 메서드를 불러와야 합니다. 이 경우, 속성을 초기화한 후 워커 데이터를 저장하기 전에 슈퍼클래스 메서드를 불러오십시오. 테스트 프레임워크는 워커에서 테스트 스위트 일부의 개수만큼 runTestSuite를 실행합니다.

    methods (Access = protected)
        function runTestSuite(plugin, pluginData)
            suiteSize = numel(pluginData.TestSuite);
            groupNumber = pluginData.Group;
            fprintf('### Running a total of %d tests in group %d\n', ...
                suiteSize, groupNumber);
            plugin.NumPassingAssertions = 0;
            plugin.NumFailingAssertions = 0;

            runTestSuite@matlab.unittest.plugins.TestRunnerPlugin(...
                plugin, pluginData);

            assertionStruct = struct('Passing', plugin.NumPassingAssertions, ...
                'Failing', plugin.NumFailingAssertions);
            plugin.storeIn(pluginData.CommunicationBuffer, assertionStruct);
        end
    end

테스트별 데이터를 저장하기 위해 runTestSuite 구현에는 Parallelizable 인터페이스의 storeIn 메서드에 대한 호출이 포함됩니다. 워커가 클라이언트에 보고해야 경우에는 storeInretrieveFrom과 함께 사용하십시오. 이 예제의 경우, 슈퍼클래스 메서드에서 반환된 후 NumPassingAssertionsNumFailingAssertions에는 테스트 그룹에 상응하는 통과 어설션 개수와 실패 어설션 개수가 포함되어 있습니다. storeIn이 워커 데이터를 하나의 입력 인수로 받기 때문에 assertionStruct는 두 개의 필드를 사용하여 어설션 개수를 그룹화합니다.

최종 테스트 스위트 일부의 보고 확장하기

reportFinalizedSuite를 확장하여 최종 테스트 스위트 일부 각각에 대한 테스트 데이터를 가져오는 방법으로 어설션 개수를 집계할 수 있습니다. 테스트 스위트 일부에 대해 저장된 assertionStruct를 가져오려면 reportFinalizedSuite 범위 내에서 retrieveFrom 메서드를 불러오십시오. 필드 값을 대응하는 클래스 속성에 추가하고 슈퍼클래스 메서드를 불러오십시오. 테스트 프레임워크는 클라이언트에서 테스트 스위트 일부의 개수만큼 이 메서드를 실행합니다.

    methods (Access = protected)
        function reportFinalizedSuite(plugin, pluginData)
            assertionStruct = plugin.retrieveFrom(pluginData.CommunicationBuffer);
            plugin.FinalizedNumPassingAssertions = ...
                plugin.FinalizedNumPassingAssertions + assertionStruct.Passing;
            plugin.FinalizedNumFailingAssertions = ...
                plugin.FinalizedNumFailingAssertions + assertionStruct.Failing;

            reportFinalizedSuite@matlab.unittest.plugins.TestRunnerPlugin(...
                plugin, pluginData);
        end
    end

헬퍼 메서드 정의하기

private 액세스 권한이 있는 methods 블록에서 세 개의 헬퍼 메서드를 정의하십시오. 이러한 메서드는 실행 중인 각 테스트 스위트 일부 내에서 통과 어설션 개수 또는 실패 어설션 개수를 늘리고 어설션 수 요약을 출력합니다.

    methods (Access = private)
        function incrementPassingAssertionsCount(plugin)
            plugin.NumPassingAssertions = plugin.NumPassingAssertions + 1;
        end

        function incrementFailingAssertionsCount(plugin)
            plugin.NumFailingAssertions = plugin.NumFailingAssertions + 1;
        end

        function printAssertionSummary(plugin)
            fprintf('%s\n', repmat('_', 1, 30))
            fprintf('Total Assertions: %d\n', plugin.FinalizedNumPassingAssertions + ...
                plugin.FinalizedNumFailingAssertions)
            fprintf('\t%d Passed, %d Failed\n', plugin.FinalizedNumPassingAssertions, ...
                plugin.FinalizedNumFailingAssertions)
        end
    end

플러그인 클래스 정의 요약

다음 코드는 AssertionCountingPlugin의 전체 내용을 제공합니다.

classdef AssertionCountingPlugin < ...
        matlab.unittest.plugins.TestRunnerPlugin & ...
        matlab.unittest.plugins.Parallelizable
    
    properties (SetAccess = private)
        NumPassingAssertions
        NumFailingAssertions
        FinalizedNumPassingAssertions
        FinalizedNumFailingAssertions
    end
    
    methods (Access = protected)
        function runSession(plugin, pluginData)
            suiteSize = numel(pluginData.TestSuite);
            fprintf('## Running a total of %d tests\n\n', suiteSize);
            plugin.FinalizedNumPassingAssertions = 0;
            plugin.FinalizedNumFailingAssertions = 0;
            
            runSession@matlab.unittest.plugins.TestRunnerPlugin(plugin, pluginData);
            
            fprintf('## Done running tests\n')
            plugin.printAssertionSummary()
        end
        
        function fixture = createSharedTestFixture(plugin, pluginData)
            fixture = createSharedTestFixture@...
                matlab.unittest.plugins.TestRunnerPlugin(plugin, pluginData);
            
            fixture.addlistener('AssertionPassed', ...
                @(~,~)plugin.incrementPassingAssertionsCount);
            fixture.addlistener('AssertionFailed', ...
                @(~,~)plugin.incrementFailingAssertionsCount);
        end
        
        function testCase = createTestClassInstance(plugin, pluginData)
            testCase = createTestClassInstance@...
                matlab.unittest.plugins.TestRunnerPlugin(plugin, pluginData);
            
            testCase.addlistener('AssertionPassed', ...
                @(~,~)plugin.incrementPassingAssertionsCount);
            testCase.addlistener('AssertionFailed', ...
                @(~,~)plugin.incrementFailingAssertionsCount);
        end
        
        function testCase = createTestMethodInstance(plugin, pluginData)
            testCase = createTestMethodInstance@...
                matlab.unittest.plugins.TestRunnerPlugin(plugin, pluginData);
            
            testCase.addlistener('AssertionPassed', ...
                @(~,~)plugin.incrementPassingAssertionsCount);
            testCase.addlistener('AssertionFailed', ...
                @(~,~)plugin.incrementFailingAssertionsCount);
        end
        
        function runTestSuite(plugin, pluginData)
            suiteSize = numel(pluginData.TestSuite);
            groupNumber = pluginData.Group;
            fprintf('### Running a total of %d tests in group %d\n', ...
                suiteSize, groupNumber);
            plugin.NumPassingAssertions = 0;
            plugin.NumFailingAssertions = 0;
            
            runTestSuite@matlab.unittest.plugins.TestRunnerPlugin(...
                plugin, pluginData);
            
            assertionStruct = struct('Passing', plugin.NumPassingAssertions, ...
                'Failing', plugin.NumFailingAssertions);
            plugin.storeIn(pluginData.CommunicationBuffer, assertionStruct);
        end
        
        
        function reportFinalizedSuite(plugin, pluginData)
            assertionStruct = plugin.retrieveFrom(pluginData.CommunicationBuffer);
            plugin.FinalizedNumPassingAssertions = ...
                plugin.FinalizedNumPassingAssertions + assertionStruct.Passing;
            plugin.FinalizedNumFailingAssertions = ...
                plugin.FinalizedNumFailingAssertions + assertionStruct.Failing;
            
            reportFinalizedSuite@matlab.unittest.plugins.TestRunnerPlugin(...
                plugin, pluginData);
        end
    end
    
    methods (Access = private)
        function incrementPassingAssertionsCount(plugin)
            plugin.NumPassingAssertions = plugin.NumPassingAssertions + 1;
        end
        
        function incrementFailingAssertionsCount(plugin)
            plugin.NumFailingAssertions = plugin.NumFailingAssertions + 1;
        end
        
        function printAssertionSummary(plugin)
            fprintf('%s\n', repmat('_', 1, 30))
            fprintf('Total Assertions: %d\n', plugin.FinalizedNumPassingAssertions + ...
                plugin.FinalizedNumFailingAssertions)
            fprintf('\t%d Passed, %d Failed\n', plugin.FinalizedNumPassingAssertions, ...
                plugin.FinalizedNumFailingAssertions)
        end
    end
end

예제 테스트 클래스 생성하기

현재 폴더에서 다음 파라미터화된 테스트 클래스가 포함된 파일 ExampleTest.m을 생성하십시오. 이 클래스는 300개의 Test 요소를 갖게 되고, 이 중 100개는 1에서 10 사이의 정수형 의사 난수를 비교하는 어설션 테스트입니다.

classdef ExampleTest < matlab.unittest.TestCase
    
    properties (TestParameter)
        num1 = repmat({@()randi(10)}, 1, 10);
        num2 = repmat({@()randi(10)}, 1, 10);
    end
    
    methods(Test)
        function testAssert(testCase, num1, num2)
            testCase.assertNotEqual(num1(), num2())
        end
        function testVerify(testCase, num1, num2)
            testCase.verifyNotEqual(num1(), num2())
        end
        function testAssume(testCase, num1, num2)
            testCase.assumeNotEqual(num1(), num2())
        end
    end
end

TestRunner에 플러그인 추가하고 테스트 실행하기

명령 프롬프트에서, ExampleTest 클래스로부터 테스트 스위트를 만듭니다.

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

suite = TestSuite.fromClass(?ExampleTest);

플러그인이 없는 TestRunner 인스턴스를 만드십시오. 다음 코드는 자동 실행기를 만들고 설치된 플러그인에 대한 제어권을 사용자에게 제공합니다.

runner = TestRunner.withNoPlugins;

실행기에 AssertionCountingPlugin을 추가하고 병렬로 테스트를 실행하십시오. 또한, 실행기에서 run 메서드를 불러오면 동일한 테스트를 직렬 모드로 실행할 수도 있습니다.

runner.addPlugin(AssertionCountingPlugin)
result = runner.runInParallel(suite);
Starting parallel pool (parpool) using the 'local' profile ...
Connected to the parallel pool (number of workers: 6).
## Running a total of 300 tests

Split tests into 18 groups and running them on 6 workers.
----------------
Finished Group 6
----------------
### Running a total of 18 tests in group 6

----------------
Finished Group 1
----------------
### Running a total of 20 tests in group 1

----------------
Finished Group 2
----------------
### Running a total of 20 tests in group 2

----------------
Finished Group 3
----------------
### Running a total of 19 tests in group 3

----------------
Finished Group 4
----------------
### Running a total of 19 tests in group 4

----------------
Finished Group 5
----------------
### Running a total of 18 tests in group 5

----------------
Finished Group 7
----------------
### Running a total of 18 tests in group 7

----------------
Finished Group 8
----------------
### Running a total of 17 tests in group 8

----------------
Finished Group 9
----------------
### Running a total of 17 tests in group 9

-----------------
Finished Group 10
-----------------
### Running a total of 17 tests in group 10

-----------------
Finished Group 11
-----------------
### Running a total of 16 tests in group 11

-----------------
Finished Group 12
-----------------
### Running a total of 16 tests in group 12

-----------------
Finished Group 15
-----------------
### Running a total of 15 tests in group 15

-----------------
Finished Group 14
-----------------
### Running a total of 15 tests in group 14

-----------------
Finished Group 17
-----------------
### Running a total of 14 tests in group 17

-----------------
Finished Group 16
-----------------
### Running a total of 14 tests in group 16

-----------------
Finished Group 13
-----------------
### Running a total of 15 tests in group 13

-----------------
Finished Group 18
-----------------
### Running a total of 12 tests in group 18

## Done running tests
______________________________
Total Assertions: 100
	88 Passed, 12 Failed

참고 항목

| | | | | | | |

관련 항목