Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,35 @@ covPlugin = matlab.unittest.plugins.CodeCoveragePlugin.forFolder("code", "Produc
obj = examplesTester(["examples", "doc"], CodeCoveragePlugin = covPlugin);
obj.executeTests;
```
## Integration with MATLAB's BuildTool
From MATLAB R2025a and onwards, users can use the `ExampleDrivenTesterTask`, a ready-to-use buildtool task shipped with ExamplesDrivenTester for automated example testing.

When you install the toolbox in MATLAB R2025a+, you'll automatically get this pre-configured task that you can use directly in your build files.

### Usage Examples
Add the **ExamplesDrivenTester** task to your buildfile.m using the following patterns:

1. Run MATLAB scripts from specified folders and generate a test report (default behavior):
```matlab
plan("runExample") = ExampleDrivenTesterTask(["examples", "doc"]);
```

2. Run MATLAB scripts but do NOT generate a test report:
```matlab
plan("runExample") = ExampleDrivenTesterTask(["examples", "doc"], CreateTestReport = false);
```

3. Run MATLAB scripts and generate a test report in PDF format:
```matlab
plan("runExample") = ExampleDrivenTesterTask(["examples", "doc"], TestReportFormat = "pdf");
```
4. Run MATLAB scripts and generate a code coverage report for code placed in the code folder:
```matlab

reportFormat = matlab.unittest.plugins.codecoverage.CoverageReport('coverage-report');
covPlugin = matlab.unittest.plugins.CodeCoveragePlugin.forFolder("code", "Producing", reportFormat);
plan("runExample") = ExampleDrivenTesterTask(["examples", "doc"], CodeCoveragePlugin = covPlugin);
```

## License

Expand Down
8 changes: 8 additions & 0 deletions buildfile.m
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
function plan = buildfile
import matlab.buildtool.tasks.CodeIssuesTask
import matlab.buildtool.tasks.TestTask
import matlab.buildtool.tasks.CleanTask

% Create a plan from task functions
plan = buildplan(localfunctions);

% Add a task to identify code issues
plan("check") = CodeIssuesTask;

plan("clean") = CleanTask;

plan("test") = TestTask('./tests');

% Run MATLAB scripts from specified folder and generate a code coverage report
reportFormat = matlab.unittest.plugins.codecoverage.CoverageReport('coverage-report');
covPlugin = matlab.unittest.plugins.CodeCoveragePlugin.forFolder("toolbox/sampleToolbox/code", "Producing", reportFormat);
plan("runExample") = ExampleDrivenTesterTask("toolbox/sampleToolbox/examples", CodeCoveragePlugin = covPlugin);

plan.DefaultTasks = "test";

end
Expand Down
17 changes: 13 additions & 4 deletions resources/project/Project.xml
Original file line number Diff line number Diff line change
Expand Up @@ -325,14 +325,23 @@
<Info Name="ExamplesDrivenTester"/>
</Info>
<ProjectPath Location="Root">
<Reference Location="cc363181-1648-4421-ac4e-2d6d7648de9e">
<Info Ref="toolbox" Type="Relative"/>
<Reference Location="3662407c-76fc-4fb3-8e7e-6fce62c1d9b5">
<Info Ref="toolbox/sampleToolbox" Type="Relative"/>
</Reference>
<Reference Location="86dfaf43-70b9-417d-9678-50d5e3603b4d">
<Info Ref="" Type="Relative"/>
</Reference>
<Reference Location="91083c4d-aa37-472b-8349-2152971d6b33">
<Info Ref="toolbox/internal" Type="Relative"/>
</Reference>
<Reference Location="63162818-a3e7-4c1d-beed-3f8397983d80">
<Info Ref="" Type="Relative"/>
<Reference Location="c5fd201e-1476-499f-88cc-f6a34a4b40cd">
<Info Ref="toolbox/sampleToolbox/examples" Type="Relative"/>
</Reference>
<Reference Location="cc363181-1648-4421-ac4e-2d6d7648de9e">
<Info Ref="toolbox" Type="Relative"/>
</Reference>
<Reference Location="df5c02f8-c778-4ad0-aa2f-7169b0afefeb">
<Info Ref="toolbox/sampleToolbox/code" Type="Relative"/>
</Reference>
</ProjectPath>
<Files Location="MLTestManagerCoverageSettings">
Expand Down
81 changes: 81 additions & 0 deletions toolbox/internal/ExampleDrivenTesterTask.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
classdef ExampleDrivenTesterTask < matlab.buildtool.Task
% Buildtool task to run example scripts with optional test & coverage reports.
% Inputs:
% - Folders: string array of M-script locations
% Optional Inputs:
% - CreateTestReport (logical)
% - TestReportFormat (string)
% - ReportOutputFolder (string)
% - CodeCoveragePlugin (object)

properties
Folders (1,:) string
CreateTestReport (1,1) logical
TestReportFormat (1,1) string
OutputPath (1,1) string
CodeCoveragePlugin
end

methods
function task = ExampleDrivenTesterTask(folders, options)
% Constructor
arguments
folders (1,:) string
options.CreateTestReport (1,1) logical = true
options.TestReportFormat (1,1) string = "html"
options.OutputPath(1,1) string = "reports"
options.CodeCoveragePlugin = []
end

task.Description = "Run published examples";
task.Inputs = folders;

% Basic validation
mustBeMember(options.TestReportFormat, ["html", "pdf", "docx", "xml"]);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move this validation to arguments blocks itself?

for f = folders
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this also be moved to arguments block?

if ~isfolder(f)
error("ExampleDrivenTesterTask:FolderNotFound", ...
"Folder not found: %s", f);
end
end

task.Folders = folders;
task.CreateTestReport = options.CreateTestReport;
task.TestReportFormat = options.TestReportFormat;
task.OutputPath= options.OutputPath;
task.CodeCoveragePlugin= options.CodeCoveragePlugin;

if task.CreateTestReport
task.Outputs = task.OutputPath;
else
task.Outputs = string.empty;
end
end
end

methods (TaskAction, Sealed, Hidden)

function runExampleTests(task, ~)
if task.CreateTestReport && ~isfolder(task.OutputPath)
mkdir(task.OutputPath);
end

if isempty(task.CodeCoveragePlugin)
examplesRunner = examplesTester( ...
task.Folders, ...
CreateTestReport = task.CreateTestReport, ...
TestReportFormat = task.TestReportFormat, ...
OutputPath = task.OutputPath);
else
% Pass CodeCoveragePlugin through when provided
examplesRunner = examplesTester( ...
task.Folders, ...
CreateTestReport = task.CreateTestReport, ...
TestReportFormat = task.TestReportFormat, ...
OutputPath = task.OutputPath, ...
CodeCoveragePlugin = task.CodeCoveragePlugin);
end
examplesRunner.executeTests;
end
end
end