Another Way to Test Ajax Methods
A while ago, Chad posted about how to test Ajax methods with QUnit. I’m also testing Ajax calls, but taking a different approach I thought I would share.
Chad’s approach was to put a timer in the test and waiting a while before performing the assertion. Another way is to hook into JQuery global ajax events, like the ajaxComplete event. Here’s some sample code that makes a call to the Flickr API via jsonp.
var url = "http://api.flickr.com/services/feeds/photos_public.gne?tags=austin,tx&format=json&jsoncallback=?"; $(document).ready(function(){ test("should get results from getJson call",function(){ expect(1); var results; $(document).ajaxComplete(function(){ start(); equals(results.title,"Recent Uploads tagged austin and tx","actual: " + results.title); }); stop(); $.getJSON(url,null,function(data){ results = data; }); }) });
Avoid Testing Ajax Calls in Unit Tests
Huh? You just showed me a way to do it, why should I avoid it? Making an Ajax call is just like making a database call, which should only be done for integration style tests. Just as you would stub a data repository method call in C#, you should do the same for AJAX calls. Except in JavaScript, this is 10 time easier because of it’s a dynamic, functional language. You can easily stub out method calls by replacing the method.
In this case I am testing against the title property, so I need a stub that looks like the getJSON method and returns back the title property.
Here is the same test, but with a stubbed out getJSON method.
var stubbedJSON = function(url,data,callback,format){ callback({title:"fake results"}); }; var originalJSON = $.getJSON; module("stubbing out getJSON", {setup: function(){ $.getJSON = stubbedJSON; }, teardown: function(){ $.getJSON = originalJSON; }}) test("getJSON should be stubbed",function(){ expect(1); $.getJSON(url,null,function(data){ equals(data.title,"fake results"); }); });
One thing that I learned the hard way with QUnit tests is that whenever you stub a method, it stays stubbed for ALL of the test on the test page. To get around that, I store the original method in a variable, then reset the method manually in the teardown. This keeps my changes isolated for each test.
Now I’m able to test the logic of my JavaScript isolated from the data coming back from my data service. Notice how easy it was to stub out the method. No complicated mocking tool required. One you embrace the dynamic_ **and_ the functional nature of JavaScript, you can do a lot more with the language than you expected. I’m appreciating JavaScript a lot more these days.