Write Tests That Use App Testing and Mocking Frameworks
This example shows how to write a test that uses the app testing framework and the mocking framework. The app contains a file selection dialog box and a label indicating the selected file. To test the app programmatically, use a mock object to define the behavior of the file selector.
Create App
Create the launchApp
app in your current
working folder. The app allows a user to select an input file and displays the
name of the file in the app. The file selection dialog box is a blocking modal
dialog box that waits for user input.
function app = launchApp f = uifigure; button = uibutton(f,'Text','Input file'); button.ButtonPushedFcn = @(src,evt)pickFile; label = uilabel(f,'Text','No file selected'); label.Position(1) = button.Position(1) + button.Position(3) + 25; label.Position(3) = 200; % Add components to an App struct for output app.UIFigure = f; app.Button = button; app.Label = label; function file = pickFile() [file,folder,status] = uigetfile('*.*'); if status label.Text = file; end end end
To explore the properties of this app prior to testing, create an instance
of the app at the command prompt. This step is not necessary for the tests,
but it is helpful to explore the properties used by the app tests. For
example, use app.Button
to access the Input
file button within the app object.
app = launchApp;
Test App With Manual Intervention
Create the LaunchAppTest
class without
using mocks. The test assumes the file input2.txt
exists in
your current working folder. If it does not exist, create it. The test presses
the Input file button programmatically and verifies that
the label matches 'input2.txt'
. You must manually select the
file.
classdef LaunchAppTest < matlab.uitest.TestCase properties TestFile = 'input2.txt'; end methods(TestClassSetup) function checkTestFiles(tc) import matlab.unittest.constraints.IsFile tc.assumeThat(tc.TestFile,IsFile) end end methods (Test) function testInputButton(tc) app = launchApp; tc.addTeardown(@close,app.UIFigure); tc.press(app.Button); tc.verifyEqual(app.Label.Text,tc.TestFile) end end end
Run the test. When the file selection dialog box appears, select
input2.txt
to allow MATLAB to proceed with the test.
Selecting any other file results in a test failure.
results = runtests('LaunchAppTest');
Running LaunchAppTest . Done LaunchAppTest __________
Create Fully Automated Test
To test the app without manual intervention, use the mocking framework. Modify the app to accept a file-choosing service instead of implementing it in the app (dependency injection).
Create a FileChooser
service with an
Abstract
method that implements the file selection
functionality.
classdef FileChooser % Interface to choose a file methods (Abstract) [file,folder,status] = chooseFile(chooser,varargin) end end
Create a default FileChooser
that uses the
uigetfile
function for file selection.
classdef DefaultFileChooser < FileChooser methods function [file,folder,status] = chooseFile(chooser,varargin) [file,folder,status] = uigetfile(varargin{:}); end end end
Change the app to accept an optional FileChooser
object. When called with no inputs, the app uses an instance of
DefaultFileChooser
.
function app = launchApp(fileChooser) if nargin==0 fileChooser = DefaultFileChooser; end f = uifigure; button = uibutton(f,'Text','Input file'); button.ButtonPushedFcn = @(src,evt)pickFile(fileChooser); label = uilabel(f,'Text','No file selected'); label.Position(1) = button.Position(1) + button.Position(3) + 25; label.Position(3) = 200; % Add components to an App struct for output app.UIFigure = f; app.Button = button; app.Label = label; function file = pickFile(fileChooser) [file,folder,status] = fileChooser.chooseFile('*.*'); if status label.Text = file; end end end
Make the following modifications to
LaunchAppTest
.
Change the test to inherit from both
matlab.uitest.TestCase
andmatlab.mock.TestCase
.Remove the
properties
block and theTestClassSetup
block. Because the mock defines the output of thechooseFile
method call, the test does not rely on the existence of an external file.Change the
testInputButton
test method so that it will do these things.Create a mock object of the
FileChooser
.Define mock behavior such that when the
chooseFile
method is called with the input'*.*'
, the outputs are the test file name ('input2.txt'
), the current working folder, and a selected filter index of 1. These outputs are analogous to the outputs from theuigetfile
function.Press the button and verify the selected file name. These steps are the same as in the original test, but the mock assigns the output values, so you do not need to interact with the app to continue testing.
To test the Cancel button, add a test method
testInputButton_Cancel
so that it will do these things.Create a mock object of the
FileChooser
.Define mock behavior such that when the
chooseFile
method is called with the input'*.*'
, the outputs are the test file name ('input2.txt'
), the current working folder, and a selected filter index of 0. These outputs are analogous to the outputs from theuigetfile
function if a user selects a file and then chooses to cancel.Press the button and verify that the test calls the
chooseFile
method and that the label indicates that no file was selected.
classdef LaunchAppTest < matlab.uitest.TestCase & matlab.mock.TestCase methods (Test) function testInputButton(tc) import matlab.mock.actions.AssignOutputs fname = 'myFile.txt'; [mockChooser,behavior] = tc.createMock(?FileChooser); when(behavior.chooseFile('*.*'),AssignOutputs(fname,pwd,1)) app = launchApp(mockChooser); tc.addTeardown(@close,app.UIFigure); tc.press(app.Button); tc.verifyEqual(app.Label.Text,fname); end function testInputButton_Cancel(tc) import matlab.mock.actions.AssignOutputs [mockChooser, behavior] = tc.createMock(?FileChooser); when(behavior.chooseFile('*.*'),AssignOutputs('myFile.txt',pwd,0)) app = launchApp(mockChooser); tc.addTeardown(@close,app.UIFigure); tc.press(app.Button); tc.verifyCalled(behavior.chooseFile('*.*')); tc.verifyEqual(app.Label.Text,'No file selected'); end end end
Run the tests. The tests run to completion without manual file selection.
results = runtests('LaunchAppTest');
Running LaunchAppTest .. Done LaunchAppTest __________
See Also
matlab.mock.TestCase
| matlab.uitest.TestCase