odoe

Testing your code

Blog Post created by odoe on Sep 2, 2015

esrijs-intern.png

You write badass apps. Your users are happy, you're happy, everything is peachy. Someone says they want some new features. You're like rad dude, I got this. You start writing and refactoring, adding new modules, tweaking a couple of others and somewhere along the line your entire application comes crashing down. Something broke and you've made so many changes you can't tell what broke where.

 

You are so screwed.

 

Maybe you've never been in such a horrible scenario, but I bet you've had to do some ugly stuff in your code to make things work because you needed to work around some weird issue that popped up while adding new features.

 

The shame

As developers, we all feel like we should do it. Maybe we start a new project with enthusiasm doing it. We should be testing our code. I'm guilty of starting a project with lots of tests, but somewhere along the way I don't keep it up and I feel horrible about it. But it doesn't have to be that way. Unit tests are appropriate for large projects, trust me. Maybe it's TDD or BDD or you just write tests after the fact. However you do it, you will only thank yourself down the road as a project grows.

 

Here is a repo on testing from previous Esri Dev Summits and a cool Karma example. I like Karma, it's a cool test runner, but recently I've revisited TheIntern for testing. Intern is really cool and you can read some really great posts on SitePen about it. Check out the one on InternRecorder which is awesome.

 

Simplify your flow

The only drawback on Intern from something like Karma that I could never get to work is have it run my tests in the terminal on every file change, but I've worked around that using live-reload in my development toolkit.

 

Combine live-reload with Grunt and a few plugins and every time I make a change to my app, my app reloads in the browser and my test page also reloads so I can instantly see if I broke something.

 

intern-test-page.png

 

Green is a beautiful color.

 

Now I'm not going to get into the whole red/green/refactor bit of tdd or unit testing. There are plenty of tutorials out there to help you out with that. There's also a whole world out there on spies and mocks for testing. I'll just say that I like SinonJS for this purpose. I know it and I'm used to it, but others may have different preferences.

 

So what's a sample test look like? Like this maybe.

define(function(require) {
  var registerSuite = require('intern!object');
  var expect = require('intern/chai!expect');
  var View = require('app/components/map/WebMapView');
  var topic = require('dojo/topic');
  var config = require('app/config');
  var utils = require('esri/arcgis/utils');
  var chai = require('intern/chai!');
  var sinon = require('sinon');
  var sinonChai = require('sinon-chai');
  chai.use(sinonChai);
  var mapView;
  registerSuite({
    name: 'components: WebMapView',
    setup: function() {
      // set up test here
      sinon.stub(utils, 'createMap').returns({
        then: function(){}
      });
    },
    beforeEach: function() {
      // run before
    },
    afterEach: function() {
      // run after
      if (mapView && mapView.destroy) {
        mapView.destroy();
      }
    },
    teardown: function() {
      // destroy widget
      utils.createMap.restore();
    },
    'Component is valid': function() {
      expect(View).to.not.be.undefined;
    },
    'View publishes a valid map given a webmapid': function() {
      mapView = new View({
        webmapid: config.webmap.webmapid
      });
      expect(mapView.webmapid).to.equal(config.webmap.webmapid);
    }
  });
});

 

All that noise basically boils down to this.

'View publishes a valid map given a webmapid': function() {
  mapView = new View({
    webmapid: config.webmap.webmapid
  });
  expect(mapView.webmapid).to.equal(config.webmap.webmapid);
}

 

I'm basically saying that when I create this component, I expect it to have a webmap with the webmapid I gave the constructor. That's it. The implementation is left up to me, but the test is only concerned about the end result.

 

Tells a story

Tests are great documentation. I can't tell you how many times I've pulled up the tests for a library or framework to get a better idea of how to use it if I'm confused about something in the docs. They can be incredibly valuable resources. They don't replace documentation, but are fantastic companions.

 

There are tons of tutorials out there on JavaScript unit testing, you can read up on. A lot are based on QUnit or Jasmine, but like I said, I've grown to really like Intern. Intern integrates well with Sauce Labs, but if you don't need the full platform, you can use the local selenium driver and chromedriver. And if using Grunt, I can use grunt-run to run the driver before executing the functional tests.

 

run: {
  options: {
    wait: false
  },
  webdriver: {
    cmd: 'java',
    args: [
      '-jar',
      'tests/lib/selenium-server-standalone-2.46.0.jar',
      '-Dwebdriver.chrome.driver=node_modules/chromedriver/bin/chromedriver'
    ]
  }
}

 

But these are probably details better left for a future blog post.

 

Write some tests

I'm currently working on a Yeoman generator to help simplify this for ArcGIS JS API development, which also includes testing. It's not quite done yet, but I'm hoping to finish it up soon.

 

Now I'm not saying you have to test every little thing, but it is a good idea to test the behavior of your app.

 

Two things to consider:

  1. Writing the tests before - testing helps to guide your development.
  2. Writing the tests after - can be done, writing the app can help you get the idea down, but you run the risk of writing tests just to pass.

 

Remember I said that tests aren't concerned with the implementations of your code. You test that you pass in a and you expect result b. That's it. So it's a good way to quickly get down what you are trying to accomplish. If you write the tests after the fact, you run the risk of writing the tests to fit your code, which could be broken. BUT, if you rerun these tests as your write more code, you'll at least know if your broke something that worked earlier.

 

There are lots of resources on JavaScript testing out there. Here are a couple I can think of .

Introduction To JavaScript Unit Testing

JavaScript Testing Recipes

Intern Tutorial esri jsapi

 

Here is a demo project that includes testing and grunt tooling to help you out.

 

For more geodev tips and tricks, check out my blog.

Outcomes