Test for one of multiple exceptions in Matlab unittests - matlab

I am using Matlab's unittest to test the handling of invalid parameters.
In the test I have a line
t.verifyError(#myObject.myMethod, 'MATLAB:nonStrucReference');
which works fine in Matlab R2014a, but fails in Matlab R2016a with the message
---------------------
Framework Diagnostic:
---------------------
verifyError failed.
--> The function threw the wrong exception.
Actual Exception:
'MATLAB:structRefFromNonStruct'
Expected Exception:
'MATLAB:nonStrucReference'
I wonder if it would be possible to test whether one of the exceptions is thrown.
I know that it would be possible to write
t.verifyError(#myObject.myMethod, ?MException);
but something more specific would be better.

You would likely want to write a custom verification method which accepts a cell array of exceptions as the input.
function verifyOneOfErrors(testcase, func, identifiers, varargin)
% Ensure that a cell array was passed rather than a string
if ischar(identifiers)
identifiers = {identifiers};
end
% If the function succeeds with no errors, then we want a failure
threw_correct_error = false;
try
func()
catch ME
% Check if the identifier is in our list of approved identifiers
threw_correct_error = ismember(ME.identifier, identifiers);
end
% Do the actual verification
testcase.verifyTrue(threw_correct_error, varargin{:})
end
Another alternative is to actually get the error message identifier dynamically within your testcase by explicitly causing the error, and retrieving the identifier.
% Get a version-specific identifier for this specific error
try; a = []; a.field; catch ME; end;
% Verify that your method throws this error
t.verifyError(#myObject.myMethod, ME.identifier)

Related

How to test arguments for a figure or axis object in MATLAB 2022?

A function receives a figure or axis object object as parameter.
I want to test this as shown in the FIXME line.
Which test should be used here in order to allow all valid objects for exportgraphics?
% myexportgraphics.m
function myexportgraphics(f)
arguments
f (1,1) {}; % FIXME add a test here
end
exportgraphics(f,...);
end
This full list of validation functions is documented here:
https://uk.mathworks.com/help/matlab/matlab_prog/argument-validation-functions.html
The only relevant one for checking the input type (other than ones for specific types like "double") is mustBeUnderlyingType
You can check which types are valid using underlyingType on example objects you want to accept.
underlyingType( figure() ); % 'matlab.ui.Figure'
underlyingType( axes() ); % 'matlab.graphics.axis.Axes'
So this would check for figures
function myexportgraphics(f)
arguments
f (1,1) {mustBeUnderlyingType(f,'matlab.ui.Figure')};
end
end
However, that doesn't allow multiple variable types, so per the docs you probably want to make your own validation function
function myexportgraphics(f)
arguments
f (1,1) {mustBeExportGraphicsType(f)};
end
end
function mustBeExportGraphicsType(g)
if ~ismember( class(g), {'matlab.ui.Figure','matlab.graphics.axis.Axes'} )
eidType = 'mustBeExportGraphicsType:notExportGraphicsType';
msgType = 'Input must be a figure or axes object';
throwAsCaller(MException(eidType,msgType));
end
end
These are the requirements for a custom validation function, emphasis mine:
Functions used for validation have these design elements:
Validation functions do not return outputs or modify program state. The only purpose is to check the validity of the input value.
Validation functions must accept the value being validated as an input argument. If the function accepts more than one input argument, the first input is the value to be validated.
Validation functions rely only on the inputs. No other values are available to the function.
Validation functions throw an error if the validation fails. Using throwAsCaller to throw exceptions avoids showing the validation function itself in the displayed error message.
Creating your own validation function is useful when you want to provide specific validation that is not available using the MATLAB validation functions. You can create a validation function as a local function within the function file or place it on the MATLAB path.
As an aside, you could use ishghandle within the custom validation function which returns true for figure and axes inputs. If you didn't use the arguments validation syntax, you could instead use ishghandle with the slightly older inputParser approach to input validation, or a simple assert near the start of your function, but that's probably beyond the scope of this question.

return statement after throw error in matlab

For my simple code It seems that the return statement is not needed after the error statement.
Does that mean the function would be early terminated once error is thrown?
If the above is true, what if i do want to process with the rest of function even after an error is thrown. For example, i can still compute c = a - b in my function.
Yes, the error terminates the program.
As suggested by Hoki, use a warning instead.
Note: Your function will throw anyway, if only modifying the code to use warning. This is because the return variable c is not assigned before after the if-statement.

fatalAssertNotError-like-method in MATLAB unit test

I am writing a class-based test suite in MATLAB for a timeseries handling package. The first test in my suite needs to check whether a connection exists to a Haver database on a network drive. If the connection does not exist, then the first test should abort the rest of the suite using one of the fatalAssert methods.
One complicating factor, which I have excluded from the exposition below, but I will mention now is that I need to use an anonymous function to check the connection to Haver (unless someone has a better idea). My package handles data from multiple sources, Haver only being one of them.
I have a parent-class test suite that performs general tests for all of the sources. I then inherit this parent-class into specific child-class test suites and set specific parameters in their respective TestMethodSetup method. One of these parameters is an anonymous function, connfun, and a location, connloc, which I use in the parent-class to test the connection. The reason I do this is because the parent tests are executed first, so I would have to wait for all of those to end if I wanted to test the connection in the child class.
This also complicates the order of execution. If I want to assign the connfun in the child class, then I have to use either the TestMethodSetup or TestClassSetup of the child class (open to recommendations on which is best here) and put this connection test in the Test method of the parent class. I noticed the if I put checkConn in the TestMethodSetup and TestClassSetup of the parent class was running before that of the child class, I was unable to pass the anonymous function and the test would be incomplete.
Putting the previous point aside for a moment, this was my first attempt at writing the test in the parent-class (note that I used a fatalAssertEqual instead of a fatalAssertTrue because isconnection() does not return a logical):
methods (Test)
function checkConn(testCase)
connloc = 'pathToHaverDatabase';
connfun = #(x) isconnection(haver(x));
testCase.fatalAssertEqual(connfun(connloc), 1);
end
end
The above works when there is a connection, but the problem that I bumped into with this is that when I cannot access connloc, an error ocurrs during the call to haver(). So instead of returning a 1 or 0 from the isconnection() call that I can fatalAssertEqual on, all of checkConn errors out due to haver(). This then leads to the rest of the tests running (and failing, which is exactly what I want to avoid).
My next idea works for both cases, but it feels like bad code, and does not have the anonymous function specification described above.
methods (Test)
function checkConn(testCase)
connloc = 'pathToHaverDatabase';
connfun = #(x) isconnection(haver(x));
try
isconn = connfun(connloc);
catch
isconn = 0;
end
testCase.fatalAssertEqual(isconn, 1)
end
end
When I wrote this, I did not necessarily want to distinguish between not having access to the network drive, not being able to call the haver() function, and getting an isconnection equal to 0 because the last case covers all three. But I realized that if I did differentiate them, then it would be a bit more robust, but it's still missing the anonymous function taht I could pass from child to parent.
properties
connloc = 'pathToHaverDatabase';
end
methods (Test)
function checkDrive(testCase)
isfound = fillattrib(testCase.connloc);
testCase.fatalAssertTrue(isfound);
end
function checkHaver(testCase)
try
hav = haver(testCase.connloc);
ishaver = ~isempty(hav);
catch
ishaver = false;
end
testCase.fatalAssertTrue(ishaver);
end
function checkConn(testCase)
connfun = #(x) isconnection(haver(x));
testCase.fatalAssertEqual(connfun(testCase.connloc), 1);
end
end
Ideally, what I would want is a fatalAssert method (or something similar) that ends the test suite when its input is an error. Something that would perhaps be called fatalAssertNotError, but I don't think that exists. If it did, the last line of my first function would simply be testCase.fatalAssertNotError(connfun(connloc)) and I would not have to worry about all the cases.
I'm very open to dynamic rewrite of this whole test setup, so any specific comments or general advice are welcome!
First of all, I think the fatalAssert case is a strong use case to provide something like fatalAssertNotError. One reason why it is not part of the package is because many/most times people don't want to check whether something doesn't error, they just want to call the code, and if it errors, it fails for the test author automatically and it is much simpler. However, other qualification types like fatal assertions and assumptions perhaps point to the need to provide this so you can choose the outcome of the test in the presence of an error, in cases where you don't want it to fail (like with assumptions) or you want it to fail "more strongly" like with fatal assertions.
That being said, I am still not convinced that you can't achieve what you are ultimately trying to do without it. The question I have centers around why you can't use TestClassSetup. It is not clear to me exactly why you weren't able to customize in the derived test class to get the behavior you want. For example, does something like this work?
classdef BaseTest < matlab.unittest.TestCase
properties(Abstract)
connloc
connfun
end
methods(TestClassSetup)
function validateConnection(testCase)
% If this errors it behaves like an assertion (not fatal assertion)
% and fails all tests in the test class. If it doesn't error but
% doesn't return 1 then the assertion failure will occur.
testCase.assertEqual(connfun(connloc), 1,
'Could not establish a connection to the database');
end
end
end
classdef DerivedTest < BaseTest
properties
connloc = 'pathToHaverDatabase';
connfun = #(x) isconnection(haver(x));
end
methods(Test)
function testSomething(testCase)
% Have at least one test method to test it out
end
end
end
Hope that helps!
If you really want to use a function you can define a nested one like this:
methods (Test)
function checkConn(testCase)
connloc = 'pathToHaverDatabase';
function res = connfun(x)
try
res = isconnection(haver(x));
catch
res = false
end
end
testCase.fatalAssertEqual(connfun(connloc), 1);
end
end
Nested functions can be a bit confusing to me because of the way they share data with the parent function. There really is no difference between an anonymous function and a nested function.
The alternative is to put the function at the end of the file, outside the classdef block:
classdef ...
%...
methods (Test)
function checkConn(testCase)
connloc = 'pathToHaverDatabase';
function res = connfun(x)
try
res = isconnection(haver(x));
catch
res = false
end
end
testCase.fatalAssertEqual(connfun(connloc), 1);
end
end
%...
end
function res = connfun(x)
try
res = isconnection(haver(x));
catch
res = false
end
end
But I honestly don't understand why you need to have a function call within fatalAssertEqual. The code you have seems perfectly fine to me.

How do I get the value of a Simulink struct from the workspace within a MATLAB function?

I need to access the values of variables in MATLAB's workspace of type Simulink.parameter:
CAL_vars = dsdd('find','/path/CAL','ObjectKind','Variable','Property',{'name' 'Class' 'value' 'CAL'})
%gets ids of variables in data dictionary
i = 10
for i=1:length(CAL_vars)
var_name = dsdd('GetAttribute',CAL_vars(i),'name');
% gets names of variables in data dict
var_eval = eval(var_name); % this works in standalone script and it does exactly
% what I need, but once i put it in the function I need this for, it returns error
if (length(var_eval.Value) ==1)
if (var_eval.Value == true)
var_eval.Value = 1;
elseif (var_eval.Value == false)
var_eval.Value = 0;
else
end
end
% do something with the Value
if (errorCode ~= 0)
fprintf('\nSomething is wrong at %s\n', var_name)
end
end
The problem arises because the structs are of made by Simulink and give error, when I try to call eval(name_of_var): Undefined function 'eval' for input arguments of type 'Simulink.Parameter'.
Curiously, it seems to function properly in a stand-alone script but once I plug it into the larger function, it stops working and starts displaying error saying
Error using eval
Undefined function or variable 'name_of_var'.
The function is clearly in the workspace.
Curiously, it seems to function properly in a stand-alone script but
once I plug it into the larger function, it stops working
This is the expected behaviour. A function has its own workspace and can't directly access variables in the base workspace.
You could try using evalin instead of eval, and specify the base workspace:
evalin(ws, expression) executes expression, a character vector or
string scalar containing any valid MATLABĀ® expression using variables
in the workspace ws. ws can have a value of 'base' or 'caller' to
denote the MATLAB base workspace or the workspace of the caller
function.
In general though, there are lots of reasons for trying to avoid using eval if at all possible (see the MATLAB help for eval) and it would be best if you could find a different way of getting this data.

Matlab: How can i stop a the whole function in matlab?

I have a function in matlab calculating something. Within that function I open another function to calculate something for it.
Now in this second function I have some case where I just want to stop everything if some certain condition is true (so I want to end both functions)
I don't want an error message or anything; Is there a command for that?
If I just type in error I get some notice in red with a message such as:
error: Invalid call to error. Correct usage is:
-- Built-in Function: error (TEMPLATE, ...)
-- Built-in Function: error (ID, TEMPLATE, ...)
error: called from:
error: /usr/share/octave/3.8.1/m/help/print_usage.m at line 89, column 5
>>>error: /home/john/wpq.m at line 75, column 4
error: /home/john/test.m at line 23, column 21
if I write error('blabla') I still get:
>>>error: blabla
error: called from:
error: /home/john/wpq.m at line 75, column 4
error: /home/john/test.m at line 23, column 21
I would like to get no output because I can write one line above already something like disp('the test on this number failed').
You could try placing a try/catch block in your main function to expect the condition under which you want code execution to stop.
I don't believe that there is any one command that allows code to stop execution from a function within a function.
There are a number of ways of doing what you want. Typically error is only meant to be used for things that actually is errors. You do for example get an "index out of bounds" error if you try to access an element outside the array. In case what happens is an error you should send an error message to inform users about what happens and highlight that this is an error. However, in case you only want this particular calculation to end and not the program I would instead recommend try-catch and printing the error message in catch.
In case this is normal termination (or if only a particular function terminates unnormally and this is expected for some input) you can either use a termination condition (function [out,success] = myFun(in)) or try-catch. Both are accepted, though I use to prefer the termination condition approach for normal termination and try-catch for unnormal termination (of functions). Unnormal termination can for example be when a function have to be terminated before all output variables are calculated. I use to prefer to have an exception thrown instead of a function returning invalid values (but a c-programmer would probably argue differently).
For the record, there is a return-statement in Matlab which terminates a particular function.
It is hard to recommend a particular approach without knowing the situation you are in, but this text would give you some different options to be choose between. Know that error handling seldom have standard approaches which can be said to be "right". It is often up to the programmer to decide what is suitable and that is typically a part of the design.
Good luck!