When writing robust JavaScript code, you will probably want to throw exceptions to let programmers know when they’ve misused your API. Sure, you could throw an instance of the built-in Error object, but then during unit testing how will you tell if the exception you’re seeing is yours and not coming from somewhere else?
The solution is to use a custom exception in your method, but this opens up a whole new can of worms. JavaScript’s weak typing and poor support for sub-classing Error mean that a custom exception class can easily be created with no error message, or even worse with no stack trace!
Today, I’m going to help you solve both these problems, and introduce you to a neat, undocumented feature in QUnit that will help you unit test your methods.
Ok, let’s say you’ve written the following method for your class MyClass:
/**
*Doessomethinginteresting
*
*@paraminput{String}instructions
*/
method: function(input) {
if ((typeof input) === "string") {
// method implementation
}
thrownew namespace.InvalidInputError("Input must be a string");
}
In the above method, we throw a custom InvalidInputError exception so that during unit testing we’ll be able to tell that the method failed specifically because the input was not a string. But how do we implement this custom exception so that it has all the properties we need? Here’s a good trick:
/**
*Raisethiserrorwheneveramethodreceivesinvalidinput
*/
namespace.InvalidInputError = function(message) {
var error = new Error(message);
error.name = 'namespace.InvalidInputError';
throw error;
};
Here we’re doing something that seems strange: we’re throwing an exception any time you try to instantiate the exception class! But it turns out that implementing the Error sub-class this way lets us throw the exception in the typical manner, and creates an exception with everything we need: it has a unique name so we can differentiate it from other exceptions, it has a valid error message, and it has a valid stack trace. The only thing we can’t do with this trick is instantiate the sub-class and manipulate it afterward—but this is not a feature that we will ever need.
The last step is to create a unit test. We’re going to use QUnit. Here’s how to test our method:
test("method: non-string input throws InvalidInputError", function() {
throws(
function() {
this.myClass.method(5);
},
function(error) {
return error.name === "namespace.InvalidInputError";
}
);
});
In the above code, QUnit will execute the method with the invalid input of 5 in a try/catch block. It will then catch the generated exception and test its name attribute. If the exception is the right type then the test passes. Otherwise, if the test caused something else to throw an exception, or if no exception was thrown at all, then the test fails.
In its official documentation, QUnit’s throws feature does not accept a function. However, in practice it does. In my code, above, the second parameter is a test function. QUnit passes the caught exception to the test function, and then expects a Boolean return value: true for a test pass or false for a test fail. We can make use of this undocumented feature to test the exception’s name to see if it’s the expected exception.
That’s it! You now know how to unit test exception handling in JavaScript. Please see the included JavaScript demo file for a working example. I hope that you found this helpful and look forward to hearing your feedback.
--Jonathan
This blog post is part of a series,like the following blog postto stay tuned and get updates about more topics around software engineering with SAPUI5 and JavaScript:
http://scn.sap.com/community/developer-center/front-end/blog/2013/12/12/engineering-in-javascript