Reputation: 870
I am using QUnit to test a function which throws an error in the case of invalid inputs. I am able to test this function by embedding it within an anonymous function, but am unsure why this is necessary. If I don't do this, QUnit reports:
Died on test #4 at http://localhost:8000/qunit/throwsTest.js:1:7: sometimesThrows
Notably, this message includes the thrown error.
I have also noticed that I can make functions that don't require args work if I pass the function as an argument rather than invoke it.
Check out my fiddle to see it live.
QUnit.test("throws test", function(assert) {
function alwaysThrows() { throw "alwaysThrows"; }
function sometimesThrows(foo) {
if (foo) {
return true;
}
else {
throw "sometimesThrows";
}
}
assert.throws(alwaysThrows, "alwaysThrows throws (works)")
assert.ok(sometimesThrows(true), "sometimesThows doesn't throw (works)");
assert.throws(function() {
sometimesThrows(false);
}, "sometimesThrows throws inside anonymous function (works)");
// Where the unexpected behavior occurs.
// The error _is_ being thrown being thrown.
assert.throws(sometimesThrows(false), "sometimesThrows throws (terminates)");
});
If wrapping the function to be tested in an anonymous function is the intended method for getting this to work, if someone could explain why, I would find that illuminating in developing my intuition.
Upvotes: 1
Views: 152
Reputation: 13273
TL;DR: This is exactly how the throws()
assertion in QUnit is intended to work, and how it must work.
Long, drawn out response:
In your example you are calling the assertion with the result of the call to sometimesThrows(false)
. That is to say, in your example above, when you call the QUnit assert method (assert.throws()
) you pass in two values: the return value from sometimesThrows()
and a string message.
In other words, your example:
assert.throws(sometimesThrows(false), "sometimesThrows throws (terminates)");
is first first calling the sometimesThrows()
method with the false
argument, which executes that method immediately, thus throwing an error. But where does that error go?? The fact is, that error is thrown from your method (sometimesThrows()
) directly into the test()
that you've written, bypassing entirely the assert.throws()
call. In other words, the assert.throws()
function call will never happen as an error was thrown prior to it being called in the execution flow.
Instead, we must pass the assert.throws()
function yet another function which it can then wrap in a try...catch
block to detect whether or not an error was thrown. We could separate this out and actually pass a named function in if you prefer (versus an anonymous, inline function), but that really doesn't change anything:
QUnit.test("throws test", function(assert) { // ..
function sometimesWrapper() {
sometimesThrows(false);
}
assert.throws(sometimesWrapper, "sometimesThrows throws (terminates)");
});
Note that we do not call sometimesWrapper()
, we pass it in as an argument to the throws()
assertion method. Internally, QUnit will then wrap the actually calling of the sometimesWrapper()
in a try...catch
block so that it can determine whether the assertion passed or failed. You can see this in the source code on Github if you wish.
Upvotes: 3