In my last entry, I showed how to use Jasmine to test an ExtJS and DeftJS application. In that post, I mentioned something called Jasmine Spies. Spies allow you to easily mock methods in your application classes or monitor calls to methods. In this entry, I’d like to go over some of the capabilities that Spies bring to your testing toolbox.
The Target Methods
To start with, I’ve updated my ViewController, MainController.coffee, to detect when a user selects a company from the grid listing of companies:
Again we see how easy DeftJS makes it to handle events in the view. In this case, I’ve set up a handler for the “selectionchange” event. That handler then takes the selected Company and sets it into a currentCompany instance variable.
As I go through the various ways we can use Spies, I’ll be focusing on the way the MainController stores the current company.
Verifying a Method Call
The most basic way to use a Spy is to set one up for the method we are interested in, and then verify that the method was called while a Spec runs:
To break this down, the test:
- Waits until the asynchronous call to load the companies has finished.
- Gets a reference to the grid via the ViewController.
- Sets up a Spy on the setCurrentCompany() method by using spyOn().
- Fires a selectionchange event from the grid.
- Verifies that the setCurrentCompany() method in the ViewController was called by using the toHaveBeenCalled() matcher.
If all you care about is just knowing a method was called, this will work just fine. However, we often need to dig a little deeper to make sure things are working correctly.
Verifying Method Arguments
Most of the time, knowing a method was called is not enough. I’d probably like to make sure the method was called the right way.
This Spec does almost exactly the same thing, but you’ll notice I’m using the toHaveBeenCalledWith() matcher. This lets me specify the arguments I expect to have been passed to the method. In this case, I definitely expect the company passed to setSelectedCompany() to be the company I used when firing the selectionchange event on the grid.
Calling Through to the Original Method
In both of the previous examples, the underlying method being spied on wasn’t actually called. The Spy method kept track of whether something tried to call it, but that’s it. We can also have the Spy do its monitoring, but then turn around and call the original method:
Here, I’m verifying that the currentCompany property was actually set by firing selectionchange and then pulling back the value using getCurrentCompany(). If I needed to, I could still use the Spy behavior we’ve already looked at, like verifying arguments.
Using a Fake Method
When running a Spec, it can often be desirable to completely replace the original method with one that I’ve created just for use in testing. The original method could be something that takes a long time, or could be something that relies on external data that may not be available in the test environment. Jasmine lets us handle this situation by using a fake method:
In essence, this has the Spy do its thing (tracking method calls and arguments passed, etc.), but then runs the fake method I supplied instead of the original underlying method. In this case, I’m using andCallFake() to replace the getCurrentCompany() method and having it return a predetermined value.
Modifying the Method Arguments or Result
The last option I’d like to look at is a case where I want the Spy to keep track of the calls for me, and I still want the original method to be called. But in between, I want to intercept the original method call and manipulate it. Maybe I want to alter the arguments, or alter the result. For example:
Jasmine Spies are extremely useful and powerful, and the Specs I write for my apps leverage them heavily. If you use Jasmine but haven’t looked into Spies yet, I hope this blog entry gives you a reason to do so. You can find more information in the Jasmine docs as well. I’ll sign off for now and give you chance to go channel your inner 007.