Create a test case with uitest class using uigetfile and uiputfile
28 views (last 30 days)
Show older comments
Cristian Verdugo
on 29 Jun 2023
Commented: Cristian Verdugo
on 4 Jul 2023
Hi,
I would like to create a test case to validate the changes in our apps created with App Designer. I cannot find a clear documentation how to create tests when there are dialog box such as "uiputfile" and "uigetfile". The idea is to introduce later the test cases in our CI/CD platform similar to github.
Regards,
0 Comments
Accepted Answer
Ken Deeley
on 3 Jul 2023
Hi Cristian,
Thanks for raising this question. This is a common requirement which applies to anyone who is writing tests for an app that uses one of the modal operating system dialogs you mentioned. One way to approach this is to combine the App Testing Framework with the Mocking Framework. The latter allows you to mock the behavior of the dialog by returning the file or folder you need for test purposes.
In this situation, we need to be able to interchange the real function (when the app is running normally) and the mock function (when the app is being tested). To test standalone functions within the Mocking Framework, we need to first implement them as methods of a class.
Here is a step-by-step guide illustrating the workflow for implementing a test for an app making use of uigetfile. The full code is also attached.
Step 1
Start by creating an abstract superclass FileSelector with a uigetfile static method. We make this method static because it represents a standalone function.
classdef ( Abstract ) FileSelector
methods ( Static, Abstract )
varargout = uigetfile( varargin )
end
end
Step 2
Implement the standard uigetfile behavior in a subclass DefaultFileSelector of FileSelector that you can use whilst the app is running under normal conditions.
classdef DefaultFileSelector < FileSelector
methods ( Static )
function filename = uigetfile( varargin )
[file, path] = uigetfile( varargin{:} );
if isequal( file, 0 )
filename = "";
else
filename = fullfile( path, file );
end
end
end
end
Step 3
Modify the app to store a FileSelector object as one of its properties. In this example, we're using an App Designer app named FileSelectorApp.
classdef FileSelectorApp < matlab.apps.AppBase
...
properties (Access = ?matlab.unittest.TestCase)
FileSelector(1, 1) FileSelector = DefaultFileSelector
end
...
end
Modify the appropriate app callback(s) to use the uigetfile static method of the DefaultFileSelector class instead of the standalone uigetfile function.
function onSelectFileButtonPushed(app, event)
filepath = app.FileSelector.uigetfile(); % Previously: [file, path] = uigetfile();
...
end
Step 4
Implement the required tests. Start by deriving the test class from matlab.uitest.TestCase (to enable automated app testing) and matlab.mock.TestCase (to enable mocking).
During the test, we create a mock FileSelector object (mockFileSelector) and define how its uigetfile method behaves via the behavior object. The Mocking Framework allows you to define different types of behavior dynamically during the test process, which means you don't need to maintain separate code for multiple test cases.
In this example, we return a fixed filename MyFile.txt whenever uigetfile is called with any input signature.
Next, we inject the mock FileSelector into our running app, ensuring that when the test completes the usual uigetfile behavior is restored.
Finally, we use the App Testing Framework to operate the controls on the app that cause uigetfile to be called, and then verify the required behavior.
classdef tFileSelectorApp < matlab.uitest.TestCase & matlab.mock.TestCase
methods ( Test )
function tSelectingFileUpdatesLabel( testCase )
% Launch the app.
app = FileSelectorApp();
testCase.addTeardown( @() delete( app ) )
% Create a mock FileSelector from the abstract interface.
[mockFileSelector, behavior] = ...
testCase.createMock( ?FileSelector );
% Define test behavior: when uigetfile is invoked with any
% inputs, return the string "MyFile.txt".
testFilename = "MyFile.txt";
when( withAnyInputs( behavior.uigetfile() ), ...
matlab.mock.actions.AssignOutputs( testFilename ) )
% Inject the mock file selector into the app. Ensure that the
% usual file selection behavior is restored after the test.
app.FileSelector = mockFileSelector;
testCase.addTeardown( @() revertFileSelector() )
% Press the button to trigger the callback that uses uigetfile.
testCase.press( app.SelectFileButton )
% Perform the test.
testCase.verifyEqual( string( app.SelectedFileLabel.Text ), ...
testFilename, "Selecting the file " + testFilename + ...
" did not update the label text to " + testFilename + "." )
% Function to restore the default file selector in the app when
% the test completes.
function revertFileSelector()
app.FileSelector = DefaultFileSelector();
end
end
end
end
Reference:
Best wishes,
Ken
More Answers (0)
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!