В этом примере показано, как создать пользовательский плагин, поддерживающий параллельное выполнение тестов. Пользовательский плагин подсчитывает количество проходных и неудачных утверждений для набора тестов. Для расширения TestRunner, плагин переопределяет методы выбора matlab.unittest.plugins.TestRunnerPlugin класс. Кроме того, для поддержки параллельных тестов плагин подкласс matlab.unittest.plugins.Parallelizable интерфейс. Для параллельного выполнения тестов требуется Toolbox™ Parallel Computing.
В файле текущей папки создайте класс подключаемого модуля с возможностью параллелизма AssertionCountingPlugin, который наследует от обоих TestRunnerPlugin и Parallelizable классы. Полный код для AssertionCountingPlugin, см. раздел Сводка по определению класса подключаемого модуля.
Чтобы отслеживать количество проходных и неудачных утверждений, определите четыре свойства только для чтения в properties блок. Каждый работник MATLAB ® в текущем параллельном пуле использует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 (см. раздел Определение вспомогательных методов).
Добавить прослушиватели в AssertionPassed и AssertionFailed события для подсчета утверждений. Чтобы добавить эти прослушиватели, расширьте методы, используемые платформой тестирования для создания содержимого теста. Содержимое теста включает TestCase экземпляры для каждого Test элемент, уровень класса TestCase экземпляры для TestClassSetup и TestClassTeardown блоки методов и Fixture экземпляры, используемые при TestCase класс имеет SharedTestFixtures атрибут.
Вызовите соответствующий метод суперкласса при переопределении методов создания. Методы создания возвращают содержимое, которое платформа тестирования создает для каждого из соответствующих контекстов. При реализации одного из этих методов с использованием incrementPassingAssertionsCount и incrementFailingAssertionsCount
вспомогательные методы, добавьте прослушиватели, требуемые плагином, в возвращенный 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
В командной строке создайте набор тестов из 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
addlistener | matlab.unittest.fixtures.Fixture | matlab.unittest.plugins.Parallelizable | matlab.unittest.plugins.TestRunnerPlugin | matlab.unittest.TestCase | matlab.unittest.TestResult | matlab.unittest.TestRunner | matlab.unittest.TestSuite | runInParallel