Simple example of how to write unit tests in Matlab
A unit test is a little program that checks if some part (or unit) of your code works as expected. What arguments are there for bothering to write such tests?
- You find bugs more quickly
- It’s reassuring to first run your tests when you haven’t touched your codes
- Check if anything brakes if you change your code
- Writing test also nudges you to keep functions small, as it’s more difficult to test functions when they have many input arguments.
Matlab ships with a unit testing framework since version R2013a. (See here if you’re using an earlier version).
I didn’t find the existing examples of how to use it easy to follow, so I’m putting here an explanation of how to test one individual function.
You can find all codes here.
Say we have a function add_one.m
we want to test:
For our unit test, we then write an additional script which we have to name with either test_
at the beginning or _test
at the end. So here’s the new script test_add_one.m
:
The first three lines are always required and we only need to change the function name to match the name of the file.
The following function test_normal1
is our first test case. We will pass in the value x = 1
and check that the result is indeed 2.
So now go to the Matlab command line and run:
Which returns:
There’ll be a dot for every test case for this function. In this case everything worked fine, but there would be an extensive message if an error had occured.
So let’s add some more tests:
It’s a good idea to give the functions meaningful names so that when there’s an error, we know where things went wrong. Don’t worry if the names get really long, they’ll only live in this script anyway.
The tricky thing is to think of the irregular ways the function might be used. For example, the following tests check that we get the right output even if we pass in an empty matrix or an NaN
value:
Now let’s give the function something where would expect an error. If we pass the function a string 'Hello world'
it returns a numerical vector. That’s not what we want, so let’s add
to our add_one.m
function. So now it fails if the input is not a number.
The following test case then checks if indeed an error is returned:
I use try-catch here to check if the function returns an error. There might be better ways to do this, but this works for me.
But we don’t always just have to check that results are equal, as sometimes we want to make sure that the difference is below some numerical threshold. In this case, calculate the absolute or relative error as actDiff
and check that it’s less than some acceptable error like this:
One thing I lack so far is a way to test local functions, so functions that you define within some other function and which only that function can use.
So that’s it. If somebody has ideas for improvements, please let me know!