I use a library of lazy assertions lazy-ass
in production code and in my testing code
(see testing without matchers blog post).
When testing an AngularJs promise-returning function, it is easy to test the success path,
but sometimes it is harder to test the failure path, because the thrown exception triggers
$exceptionHandler
and disrupts the entire program. Here is how I test angular code
that can throw exceptions asynchronously.
Imagine we have a service that loads a resource. If the resource cannot be loaded, the
service throws an error. We never throw an error directly, instead we using global window.la
function to only throw an error when a predicate is false
1 | function loadResource(params) { |
We can easily test the success path using Jasmine test framework and running through Karma plugin
1 | describe('loads resource', function () { |
In order to test the failure path we need to make sure we intercept and prevent la
from
firing in // 1
otherwise a global error handler will kick in. Luckily, Jasmine has built-in
method spying and mocking.
We are going to use the plain spyOn
feature.
1 | describe('throws error when load fails', function () { |
When we call spyOn(window, 'la');
Jasmine will overwrite la
method, replacing the actual
function with a spy. Thus failed(err)
function call will no longer throw an error. Instead the call will
be recorded inside the spy. We can verify that the spy has the expected call. Because window.la(...)
was called several times as part of the defensive input checks (at the start of loadResource
),
we need to verify the last call to window.la
1 | describe('throws error when load fails', function () { |
We can verify more arguments than just the error message. We could even avoid using expect
matcher and instead use the lazyAss
assertion itself. Because Jasmine only mocked window.la
,
and window.la
and window.lazyAss
are aliases to the same function, the other
alias remains fully functioning
1 | describe('throws error when load fails', function () { |
You do not need to worry about restoring the original function. When the spec finishes running, all spies are automatically restored back to the original functions.