Unit Testing Objects Dependent on ArcGIS Server Javascript API

Recently, I’ve created a custom Dojo dijit that contains a esri.Map from the ArcGIS Server Javascript API.  The dijit, right now, creates the map on the fly, so it calls new esri.Map(…) and map.addLayer(new esri.layers.ArcGISTiledMapServiceLayer(url)), for example.  This can cause heartburn when trying to unit test the operations that my custom dijit is performing.  I am going to run through the current (somewhat hackish) way I am performing unit tests without having to create a full blown HTML representation of the dijit.

I’ll be using JSpec for this example, so you may want to swing over to that site and brush up on the syntax, which is pretty easy to grok, especially if you’ve done any BDD/spec type unit testing before.

The contrived, but relatively common, scenario for this post is:

  1. My custom dijit makes a call to the server to get information about some feature.
  2. The service returns JSON with the extent of the object in question.
  3. I want my map control to go to that extent.

Following the Arrange-Act-Assert pattern for our unit tests, the vast majority of the work here will be in the Arrange part.  I don’t want to pull in the entire AGS Javascript API for my unit tests.  It’s big and heavy and I am not testing it so I don’t want it.    Also, I don’t want to invoke the call to the server in this test.  Again, it’s not really what I am testing, and it slows the tests down.  I want to test that, if my operation gets the right JSON, it sets the extent on the map properly.

The Whole Test

Here is the whole JSpec file:

describe 'VersionDiff'

 before_each
   vd = new esi.dijits.VersionDiff();
 end
 describe 'updateImages()'
   it 'should change the extent of the child map'
     //Arrange
     esri={
       Map:function(){
         this.setExtent=function(obj){
           this.extent=obj;
         };
       },
       geometry:{
         Extent:function(xmin,ymin,xmax,ymax){
           var obj={};
           obj.xmin=xmin;
           obj.ymin=ymin;
           obj.xmax=xmax;
           obj.ymax=ymax;
           return obj;
         }
       }
     };
     vd.childMap = new esri.Map();
     var text = fixture("getFeatureVersionGraphics.txt")
     text = dojo.fromJson(text)
     //Act
     vd.updateMapToFeatureExtent(text)
     //Assert
     vd.childMap.extent.xmin.should.be 7660976.8567093275
     vd.childMap.extent.xmax.should.be 7661002.6869258471
     vd.childMap.extent.ymin.should.be 704520.0600393787
     vd.childMap.extent.ymax.should.be 704553.8080708608
   end
 end
end

//Arrange

The Arrange portion of the test stubs out the methods that will be called in the esri namespace.  Since the goal of the test is to make sure my djiit changes the extent of the map, all I need to do is stub out the setExtent method on the Map.  setExtent takes an Extent object as an argument, so I create that in my local, tiny esri namespace.  Now I can set the property on my dijit  using my stubbed out map.  Thanks to closures global variables (ahem), the esri namespace I just created will be available inside my function under test.  Closures are sexy, and I only know enough about them to be dangerous.  Yay!  I don’t have to suck in all the API code for this little test.  That fixture function is provided by JSpec, and basically pulls in a text file that has the JSON I want to use for my test.  I created the fixture my saving the output of a call to my service, so now I don’t have to invoke the service inside the unit test.

//Act

This is the easy part.   Call the function under test, passing in our fixture.

//Assert

How do I know the extent was changed?  When I created my tiny esri namespace, my esri.geometry.Extent() function returns an object that has the same xmin/ymin/xmax/ymax properties of an esri.geometry.Extent object.  The setExtent() function on the map stores this object in an extent property.  All I have to do is make sure the extent values match what was in my fixture.

I didn’t include the source to the operation being tested, because I don’t think it adds much to the point.  Suffice it to say that it calls setExtent() on the childMap property.

So What?

I realize this may not be the greatest or cleanest approach, but it is serving my needs nicely.  I am sure in my next refactor of the unit tests that I’ll find a new approach that makes me hate myself for this blog post.  As always, leave a comment if you have any insight or opinion.  Oh, and regardless of this test, you should really look into JSpec for javascript unit testing.  What I show here is barely the tip of what it offers.

Reblog this post [with Zemanta]
Advertisements

About Ruprict

I am a nerd that is a Nerd Wannabe. I have more kids than should be allowed by law, a lovely wife, and a different sense of humor than most. I work in the field of GIS, where I am still trying to find myself on the map. View all posts by Ruprict

2 responses to “Unit Testing Objects Dependent on ArcGIS Server Javascript API

  • Kirk

    I’m not seeing the closure.
    “esri={” creates a global variable. I’d recommend changing it to “var esri={” and moving it into your before_each section.

    • ruprict

      Yup, you are exactly right. The before_each isn’t working either….the closure isn’t happening. I will investigate.

      Thanks for catching my silliness.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: