Запуск тестов параллельно с пользовательским плагином

В этом примере показано, как создать пользовательский плагин, который поддерживает параллельные тесты. Пользовательский плагин подсчитывает количество проходящих и неудачных утверждений для тестового набора. Расширение TestRunnerплагин переопределяет методы выбора matlab.unittest.plugins.TestRunnerPlugin класс. Кроме того, чтобы поддержать параллельные тесты, плагин подклассифицирует matlab.unittest.plugins.Parallelizable интерфейс. Чтобы запустить тесты параллельно, вам нужен Parallel Computing Toolbox™.

Создайте класс плагина

В файле в текущей папке создайте класс параллелизируемого плагина AssertionCountingPlugin, который наследует от обоих TestRunnerPlugin и Parallelizable классы. Полный код для AssertionCountingPlugin, см. «Класс плагина Определения Сводных данных».

Чтобы отслеживать количество проходящих и неудачных утверждений, задайте четыре свойства только для чтения в properties блок. Каждый MATLAB® worker в текущем параллельном пуле использует NumPassingAssertions и NumFailingAssertions отслеживать количество проходящих и неудачных утверждений при запуске фрагмента TestSuite массив. Клиент MATLAB использует FinalizedNumPassingAssertions и FinalizedNumFailingAssertions агрегировать результаты от различных работников и сообщить общее количество пройденных и неудачных утверждений в конце сеанса тестирования.

properties (SetAccess = private)
    NumPassingAssertions
    NumFailingAssertions
    FinalizedNumPassingAssertions
    FinalizedNumFailingAssertions
end

Расширение сеанса тестирования

Чтобы расширить выполнение всего TestSuite массив, переопределите runSession метод TestRunnerPlugin в methods блок с protected доступ. Среда тестирования оценивает этот метод один раз на клиенте.

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 (см. «Определение вспомогательных методов»).

Расширение создания общих испытательных стендов и образцов TestCase

Добавить прослушивателей в AssertionPassed и AssertionFailed события для подсчета утверждений. Чтобы добавить эти прослушиватели, расширьте методы, используемые средой тестирования, чтобы создать содержание теста. Содержание теста включает TestCase образцы для каждого Test элемент, уровень классов TestCase образцы для TestClassSetup и TestClassTeardown блоки методов и Fixture образцы, используемые в TestCase класс имеет SharedTestFixtures атрибут.

Активируйте соответствующий метод суперкласса, когда вы переопределяете методы создания. Методы создания возвращают содержимое, которое создает среда тестирования для каждого из соответствующих контекстов. При реализации одного из этих методов используйте incrementPassingAssertionsCount и incrementFailingAssertionsCount helper methods, добавьте прослушиватели, необходимую для плагина, к возвращенной Fixture или TestCase образец.

Добавьте эти методы создания к methods блок с protected доступ.

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 массив в различные группы и присваивает его работникам для обработки. Каждый рабочий может запустить одни или несколько фрагментов тестового набора. Чтобы настроить поведение работников, переопределите runTestSuite метод TestRunnerPlugin в methods блок с protected доступ.

Расширение 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 содержит вызов на storeIn метод Parallelizable интерфейс. Использование storeIn наряду с retrieveFrom когда работники должны отчитываться перед клиентом. В этом примере, после возвращения из метода суперкласса, NumPassingAssertions и NumFailingAssertions содержат количество проходящих и неудачных утверждений, соответствующих группе тестов. Потому что storeIn принимает рабочие данные только как один входной параметр, assertionStruct группирует счетчики значения с помощью двух полей.

Расширение отчетов о готовом фрагменте тестового набора

Расширение reportFinalizedSuite агрегировать счетчики утверждений путем извлечения тестовых данных для каждого конечного фрагмента тестового набора. Как извлечь сохраненные assertionStruct для фрагмента тестового набора вызовите retrieveFrom метод в возможности reportFinalizedSuite. Добавьте значения полей к соответствующим свойствам классов и активируйте метод суперкласса. Среда тестирования оценивает этот метод на клиенте в столько раз, сколько количество тестового набора фрагментов.

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

Определите вспомогательные методы

В methods блок с private access, задайте три вспомогательных метода. Эти методы увеличивают количество проходящих или неудачных утверждений в каждом текущем фрагменте тестового набора и печатают сводные данные количества утверждений.

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

См. также

| | | | | | | |

Похожие темы