spyOn, the method you call to spy on a function. This code is taken directly from the Jasmine documentation.
It’s simple to use
spyOn; just pass it an object, and the name of a method on that object that you want to spy on. If you look closely, you might realize that
spyOn is replacing the original function with a spy that intercepts the function calls and tracks a lot of potentially useful information about them. The problem we run into above is that once we’ve replaced the original function, we’ve lost its capabilities. We can remedy that with
andCallThrough. If you chain
andCallThrough() after calling
spyOn, the spy will then pass any calls to it through to the original function. Here’s another bit of code from the docs to show off
Sometimes you don’t want it to call through to the original. Maybe you just want the spy to return a specific value so that you can test to see what happens when that value is returned. Or maybe you just want it to return a single value for consistency’s sake. Well, you can tell a spy to return a specified value with
andReturn. It’s used similarly to
andCallThrough, but obviously it is used to return a specific value instead of calling through to the original function. It takes a single argument, which is the value to be returned.
For the final
andXxx spy method, we have
andCallfake, which will take a function argument. Rather than passing through to the original function, this method will make it so that the spy passes through to call the function that you specified as its argument. It’ll even return any values returned from your new fake function.
Now, you might be wondering, what if I don’t have an object already that I want the spy to work with? I just want to create a spy without any existing objects or functions. Is this possible? You bet! First, let’s take a look at how to create a spy function from thin air, then we’ll move on to explore the idea of making an entire spy object.
You make a spy function with
jasmine.createSpy and you pass in a name. It’ll return the spy function for you. The name seems a bit useless because it isn’t used as an identifier that we can refer to it as, but as you can see below, it can be used with the spies
identity property in error messages to specify where an error occurred. Here it is:
Finally, let’s create an object with all spy methods using
jasmine.createSpyObj. As with
createSpy, it takes a name, but it also takes an array of strings that will be used as the names of the spy functions attached to the object. The name is used the exact same way that it is used with
createSpy: identifying objects during Jasmine error results.
Asynchronous programming isn’t simple, at least not as simple as straight-forward synchronous programming. This makes people scared to test asynchronous functions even more, but Jasmine makes it really simple to test asynchronous functions too. Let’s take a look at an example using an AJAX request with jQuery:
This might not make much sense just looking at it, but with a little explanation it’ll seem dead simple and all your fears of asynchronous testing will dissipate. We’ll hop right into the body of the
it block to get started. First we created a couple flags. These aren’t always necessary, depending on how the asynchronous function works, but if you need them, these can hold Booleans that specify whether the asynchronous function worked/finished, like I did here. Now we get to the fun part:
waitsFor. The first call to
runs is where we run an asynchronous function. Then we use
waitsFor to determine when/if the asynchronous function finished. This is done by specifying a function that returns a boolean that should be true when the asynchronous work is finished or false before it finishes. This is the first argument passed in. The next one is the error we want to show if it never returns true, and the final argument is the number of milliseconds we should wait before it times out and fails the spec. The function that is passed into
waitsFor is run on short intervals until it either returns true or it times out. Then we move on and run the function passed into the next
runs call. This is generally where you do your
The fun part is that you can continue alternating between
waitsfor (potentially) inifinitely. So, if you want to run another asynchronous function in the second
runs and then do another
waitsfor and finally call
runs once again to complete your tests, it’s entirely possible. You’ll see me do this in an article soon when I talk about testing Socket.IO.
If you have code that runs with
setInterval, you can skip the asynchronous testing and just use Jasmine to control the clock, allowing you to run that code synchronously. Just tell jasmine to use its own mock clock with
jasmine.Clock.useMock() and then use
jasmine.Clock.tick([number]) to move the clock ahead whenever you want.
As simple as the asynchronous testing is, I still would rather use this when I can. It’s fun to have that much power. Of course, this doesn’t actually affect the clock, but who cares? It feels like it does, right?
Sometimes, trying to test for a specific value is too strict and you just want to make sure it is of a specific type, like a number or object. In this case
jasmine.any comes to the rescue. You can use it in any matcher to check a value’s type instead of comparing it to an exact value.
It takes a constructor name and compares it to the constructor of the value. This means, you can test it against your custom types too, not just the built in ones.
Sometimes you don’t want a spec or suite to run, whether it is because it takes too long, or you know it will fail and don’t want to deal with it until later. You could always comment it out, but then if you want to turn all of the commented out specs back on, it’s difficult to do a search and replace. Instead you can prepend
it with an “x”, and the suite or spec will be skipped just as if it was commented out, but a simple search for
xdescribe can be replaced with
describe. The same goes for
Well that’s pretty much all you need to know to get started with unit testing using the Jasmine framework. I hope that its simplicity will draw you in and that if you’ve been holding off on unit testing, you’ll start now. God bless and happy coding.