Skip to content
Merged
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
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[![MATLAB](https://github.com/simkaryote/MATLAB-SimBiology-DevOps-Workflow-Example/actions/workflows/ci.yml/badge.svg)](https://github.com/simkaryote/MATLAB-SimBiology-DevOps-Workflow-Example/actions/workflows/ci.yml)
[![Tests](https://img.shields.io/badge/Tests-Open_Test_Report-blue)](https://simkaryote.github.io/MATLAB-SimBiology-DevOps-Workflow-Example/tests/)
[![Coverage](https://img.shields.io/badge/Coverage-Open_Code_Coverage_Report-orange)](https://simkaryote.github.io/MATLAB-SimBiology-DevOps-Workflow-Example/coverage/)
[![MATLAB](https://github.com/ChezJe/MATLAB-SimBiology-DevOps-Workflow/actions/workflows/ci.yml/badge.svg)](https://github.com/ChezJe/MATLAB-SimBiology-DevOps-Workflow/actions/workflows/ci.yml)
[![Tests](https://img.shields.io/badge/Tests-Open_Test_Report-blue)](https://ChezJe.github.io/MATLAB-SimBiology-DevOps-Workflow/tests/)
[![Coverage](https://img.shields.io/badge/Coverage-Open_Code_Coverage_Report-orange)](https://ChezJe.github.io/MATLAB-SimBiology-DevOps-Workflow/coverage/)

# MATLAB<sup>&reg;</sup>/SimBiology<sup>&reg;</sup> DevOps Workflow Example

Expand Down
28 changes: 14 additions & 14 deletions WorkshopGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,19 @@ In this workshop, you will:
## Table of Contents
&#8195;[Workshop Requirements](#H_34C2FB57)

&#8195;[Part 1: Getting the workshop files and configuring GitHub for automated testing and results publishing](#TMP_7781)
&#8195;[Part 1: Getting the workshop files and configuring GitHub for automated testing and results publishing](#TMP_0858)

&#8195;[Part 2: Generating your first tests](#TMP_16c9)
&#8195;[Part 2: Generating your first tests](#TMP_7685)

&#8195;[Part 3: Finding existing tests and measuring coverage](#TMP_20d9)
&#8195;[Part 3: Finding existing tests and measuring coverage](#TMP_38e3)

&#8195;[Part 4: Updating badges, committing our changes, and pushing to GitHub](#TMP_4270)
&#8195;[Part 4: Updating badges, committing our changes, and pushing to GitHub](#TMP_9e20)

&#8195;[Part 5: Create a pull request, watch GitHub Actions automatically test your changes and publish results](#TMP_513c)
&#8195;[Part 5: Create a pull request, watch GitHub Actions automatically test your changes and publish results](#TMP_5a5c)

&#8195;[Part 6: Compile the App in the CI workflow and download the artifact](#TMP_28f0)
&#8195;[Part 6: Compile the App in the CI workflow and download the artifact](#TMP_4618)

&#8195;[Workshop wrap\-up and additional information](#TMP_457b)
&#8195;[Workshop wrap\-up and additional information](#TMP_5b6a)

<!-- End Toc -->

Expand All @@ -54,7 +54,7 @@ The following steps cover all of the things you will need to successfully comple
- The workshop leverages the free repository and CI capabilities offered by GitHub and GitHub Actions
- Go to: [https://github.com/signup](https://github.com/signup)

<a id="TMP_7781"></a>
<a id="TMP_0858"></a>

# Part 1: Getting the workshop files and configuring GitHub for automated testing and results publishing

Expand Down Expand Up @@ -248,7 +248,7 @@ Click on the 'Run App' shortcut to start the app in MATLAB:

![image_24.png](WorkshopGuide_media/image_24.png)

<a id="TMP_16c9"></a>
<a id="TMP_7685"></a>

# Part 2: Generating your first tests

Expand Down Expand Up @@ -405,7 +405,7 @@ Congratulations! You just created multiple tests for your MATLAB code!

It was easier than you thought, right?

<a id="TMP_20d9"></a>
<a id="TMP_38e3"></a>

# Part 3: Finding existing tests and measuring coverage

Expand Down Expand Up @@ -645,7 +645,7 @@ It looks like we've achieved full statement coverage for [`generateSimFun`](./co

![image_69.png](WorkshopGuide_media/image_69.png)

<a id="TMP_4270"></a>
<a id="TMP_9e20"></a>

# Part 4: Updating badges, committing our changes, and pushing to GitHub

Expand Down Expand Up @@ -794,7 +794,7 @@ At this point, all of your changes will be pushed to GitHub.

![image_89.png](WorkshopGuide_media/image_89.png)

<a id="TMP_513c"></a>
<a id="TMP_5a5c"></a>

# Part 5: Create a pull request, watch GitHub Actions automatically test your changes and publish results

Expand Down Expand Up @@ -904,7 +904,7 @@ The code coverage report looks like this:

Now anyone that visits your repository can immediately see the quality of your code, explore your test and code coverage results, and will have more confidence in the code you are writing!

<a id="TMP_28f0"></a>
<a id="TMP_4618"></a>

# Part 6: Compile the App in the CI workflow and download the artifact

Expand Down Expand Up @@ -983,7 +983,7 @@ Once the `Deploy/ Release (main)` job is done, a new artifact is available at th

You can now download the CTF file and upload it to your Web App Server!

<a id="TMP_457b"></a>
<a id="TMP_5b6a"></a>

# Workshop wrap\-up and additional information

Expand Down
14 changes: 14 additions & 0 deletions resources/project/Project.xml
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,20 @@
</Category>
</Info>
</File>
<File Location="TestSimulationModel.m">
<Info>
<Category UUID="FileClassCategory">
<Label UUID="test"/>
</Category>
</Info>
</File>
<File Location="tSimulateModel.m">
<Info>
<Category UUID="FileClassCategory">
<Label UUID="test"/>
</Category>
</Info>
</File>
</File>
<File Location=".gitattributes">
<Info/>
Expand Down
111 changes: 111 additions & 0 deletions tests/TestSimulationModel.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
% This test file was generated by Copilot. Validate generated output before use.
classdef TestSimulationModel < matlab.unittest.TestCase
% Unit tests for SimulationModel class.
%
% These tests assume that a MAT-file 'simFunction_Dose.mat' exists on the
% MATLAB path and contains variables 'simFun' and 'doseTable' compatible
% with SimulationModel constructor expectations.

properties
Model % instance of SimulationModel
end

methods(TestMethodSetup)
function createModel(testCase)
% Create a fresh instance for each test.
testCase.Model = SimulationModel();
end
end

methods(Test)
function testConstructorInitializesProperties(testCase)
% Verify constructor sets up essential properties and original values.
m = testCase.Model;

% SimFun and DoseTable should be non-empty
testCase.verifyNotEmpty(m.SimFun, 'SimFun should be loaded by constructor.');
testCase.verifyNotEmpty(m.DoseTable, 'DoseTable should be loaded by constructor.');

% Original parameter values should be numeric scalars
testCase.verifyGreaterThan(m.Kel0, 0);
testCase.verifyGreaterThan(m.Kon0, 0);
testCase.verifyGreaterThan(m.Kdeg0, 0);
testCase.verifyGreaterThan(m.Duration0, 0);
testCase.verifyGreaterThan(m.Interval0, 0);
testCase.verifyGreaterThan(m.Amount0, 0);
end

function testSimulateProducesSimDataAndTable(testCase)
% Calling simulate with default parameters should populate SimData and SimDataTable.
m = testCase.Model;

% Ensure no SimData before simulation
if ~isempty(m.SimDataTable)
% reset by creating a new instance if leftover data exists
m = SimulationModel();
testCase.Model = m;
end

% Run simulation with default parameters
m.simulate();

% SimData and SimDataTable should be set
testCase.verifyNotEmpty(m.SimData, 'SimData should be set after simulate.');
testCase.verifyNotEmpty(m.SimDataTable, 'SimDataTable should be set after simulate.');

% SimDataTable must contain Time and RO variables
testCase.verifyTrue(ismember('Time', m.SimDataTable.Properties.VariableNames), ...
'SimDataTable must contain Time column.');
testCase.verifyTrue(ismember('RO', m.SimDataTable.Properties.VariableNames), ...
'SimDataTable must contain RO column produced by simFun.');

% Dose column should exist and have NaNs except dosing times
testCase.verifyTrue(ismember('Dose', m.SimDataTable.Properties.VariableNames), ...
'SimDataTable must contain Dose column.');
doseCol = m.SimDataTable.Dose;
testCase.verifySize(doseCol, [height(m.SimDataTable), 1]);
end

function testSimulateAppliesCustomParameters(testCase)
% Verify simulate updates DoseTable.Amount and Interval when custom parameters provided.
m = testCase.Model;

originalAmount = m.DoseTable.Amount;
originalInterval = m.DoseTable.Interval;

% choose positive custom parameters: [kel, kon, kdeg, duration, amount, interval]
customParams = [m.Kel0, m.Kon0, m.Kdeg0, m.Duration0, originalAmount*2, max(1, originalInterval)];

m.simulate(customParams);

testCase.verifyEqual(m.DoseTable.Amount, customParams(5), 'Dose amount should be updated.');
testCase.verifyEqual(m.DoseTable.Interval, customParams(6), 'Dose interval should be updated.');

% SimDataTable should reflect dosing times consistent with the provided interval
dosingTimes = customParams(6)*(0:customParams(4)/customParams(6));
% At least one dosing time should be present in Time column
hasDosing = any(ismember(m.SimDataTable.Time, dosingTimes));
testCase.verifyTrue(hasDosing, 'SimDataTable.Time should include dosing times for given interval.');
end

function testROIsBetweenThresholdsLogical(testCase)
% simulate then verify ROIsBetweenThresholds returns logical scalar.
m = testCase.Model;
m.simulate();

val = m.ROIsBetweenThresholds;
testCase.verifyClass(val, 'logical');
testCase.verifySize(val, [1,1]);
end

function testSimulateWithInvalidParametersRaises(testCase)
% Passing invalid (non-positive) parameters should trigger argument validation.
m = testCase.Model;

% Create invalid parameters with a non-positive entry
invalidParams = [m.Kel0, m.Kon0, -1*m.Kdeg0, m.Duration0, m.Amount0, m.Interval0];

testCase.verifyError(@() m.simulate(invalidParams), 'MATLAB:validators:mustBePositive');
end
end
end
18 changes: 18 additions & 0 deletions tests/tSimulateModel.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
% This is an autogenerated sample test for all
classdef tSimulateModel < matlab.unittest.TestCase
methods (Test)
function testAll(testCase)
% Specify the inputs
sObj = SimulationModel;
sObj.simulate;

testCase.verifyClass(sObj.SimData, 'SimData');

import matlab.unittest.constraints.IsSameSetAs

testCase.verifyThat(sObj.SimData.DataNames,...
IsSameSetAs(["Drug","Complex","Receptor","RO"]));

end
end
end
2 changes: 1 addition & 1 deletion tests/tgenerateSimFun.m
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
end

properties (ClassSetupParameter)
MATfilename = {"test_generateSimFun.mat"}
MATfilename = {"test_generateSimFun.mat", string.empty}
end

properties (TestParameter)
Expand Down