Programmatically close App Designer app after running it for a unit test
You are now following this question
- You will see updates in your followed content feed.
- You may receive emails, depending on your communication preferences.
An Error Occurred
Unable to complete the action because of changes made to the page. Reload the page to see its updated state.
Show older comments
0 votes
I need to run mlapp myApp for a unit test, but after the test I want the app window to be closed. The only way I know to do this is to search for the app UI Figure in all graphics objects, but I feel there should be a more elegant way.
In my example there is a function appStartup that is called by myApp when the app is started, and appStartup should throw an error if the app can't be run. My code looks like:
function testAppNotRunnable(testCase)
% code here to make sure the app can't run
verifyError(testCase, @() myApp, "appStartup:cantRunApp") % appStartup errors when called by myApp
% close open app windows
h = findall(groot, 'Tag', 'my app tag');
close(h)
This works, but seems inelegant.
Accepted Answer
Original answer removed due to error. See discussion below.
Summary of approaches (thanks to Steven Lord)
- use a addTeardown
- use a try/catch block to catch errors in the startup function and close the app when there is an error
- for public functions, call the function directly from the app object within verifyError and then close the app
- If possible (outside of App Designer) reorganize code to move validation before figure creation
7 Comments
Rich006
on 16 May 2024
Pass the app handle to which function? The app is created by verifyError. If I try to define a handle to the app outside of verifyError (with app = myApp;) , then the error I'm trying to verify will happen at that time, and won't be caught by verifyError.
Adam Danz
on 16 May 2024
Oh right... I've updated my answer.
verifyError returns the app handle which can be used to close the app.
"verifyError returns the app handle which can be used to close the app."
No, it doesn't, unless the verifyError call fails to verify an error/exception. From the verifyError documentation page: "If the function handle throws an exception, all outputs are displayed as <missing>."
testcase = matlab.unittest.TestCase.forInteractiveUse;
output = verifyError(testcase, @() plus(1:2, 1:3), ...
"MATLAB:sizeDimensionsMustMatch")
Verification passed.
output = missing
<missing>
Compare to a case where the function being tested does not throw an exception (and so the verification fails.)
output = verifyError(testcase, @() plus(1:2, 1:2), ...
"MATLAB:sizeDimensionsMustMatch")
Verification failed.
---------------------
Framework Diagnostic:
---------------------
verifyError failed.
--> The function did not throw any exception.
Expected Exception:
'MATLAB:sizeDimensionsMustMatch'
Evaluated Function:
function_handle with value:
@()plus(1:2,1:2)
------------------
Stack Information:
------------------
In /tmp/Editor_xdryi/LiveEditorEvaluationHelperEeditorId.m (LiveEditorEvaluationHelperEeditorId) at 4
In /MATLAB/toolbox/matlab/connector2/interpreter/+connector/+internal/fevalMatlab.p (fevalMatlab) at 0
In /MATLAB/toolbox/matlab/connector2/interpreter/+connector/+internal/fevalJSON.p (fevalJSON) at 0
output = 1x2
2 4
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
In this case one approach you could use would be to set up a teardown using addTeardown. Record the list of figures that existed prior to the test method running as the first line of the test. Add a teardown function that queries what figures exist when the teardown function executes and closes all the figures that are in the later list but not in the former (using setdiff.)
But I'd take a closer look at the app. Why does the app create the figure then error out? Can you reorganize the initialization code to error out before it creates the figure, perhaps pulling numeric data validation earlier in the initialization function? If the app constructor throws an error before the figure gets created, you only need to worry about closing the app figure if the test fails (in which case the output argument from verifyError can help.)
Rich006
on 16 May 2024
Looks like verifyError is not actually returning a handle to the app. With close(appHandle.UIFIgure) I get
Error ID:
---------
'MATLAB:noSuchMethodOrField'
--------------
Error Details:
--------------
Unrecognized method, property, or field 'UIFigure' for class 'missing'.
Rich006
on 16 May 2024
@Steven Lord I fully agree my software could be much better designed. The appStartup function I'm testing was created by moving code out of the mlapp file, so it's already better than it was. I have two challenges here: 1) I'm building from someone else's existing code, and 2) nobody on my team (including me) has experience in professional software development. I'm not sure which is worse.
:-)
I will look at your addTeardown suggestion, but I will also look into doing the startup routine before opening the app. That might not be too hard to implement.
Another possibility could be to wrap the startup code in your appStartup function in a try / catch block. If an error occurs in the try part of the block, close the figure (if it exists) before calling rethrow on the error.
try
x = (1:2) + (1:3);
catch ME
disp("Here is where I'd close the figure.")
rethrow(ME)
end
Here is where I'd close the figure.
Arrays have incompatible sizes for this operation.
Adam Danz
on 16 May 2024
If the app subclasses from matlab.apps.AppBase I'm not aware of a way to run one of its methods (e.g. the startup function) before opening/creating the app.
However, once the app object exists, you can independently call any of its public functions. For example, if appStartup is a public function in myApp and the expected error it throws is independent of the initialization at startup, you could verify the error using,
app = myApp;
verifyError(testCase, @() appStartup(app), "appStartup:cantRunApp")
close(app.UIFigure)
But I like Steven's addTeardown idea best and wish I had thought of it.
More Answers (0)
Categories
Find more on Startup and Shutdown in Help Center and File Exchange
Tags
See Also
Select a Web Site
Choose a web site to get translated content where available and see local events and offers. Based on your location, we recommend that you select: .
You can also select a web site from the following list
How to Get Best Site Performance
Select the China site (in Chinese or English) for best site performance. Other MathWorks country sites are not optimized for visits from your location.
Americas
- América Latina (Español)
- Canada (English)
- United States (English)
Europe
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom (English)