Skip to main content

What to test when testing Javascript

Part two in the series Test Driven Development with Javascript.



By now you've probably read and heard a lot warning you off testing through the UI and testing the user interface generally. Those still holds true for Javascript so you may be wondering if there is anything left to test. Time for some code!

Not very testable code

function validate() {
    if(document.simple_form.name.value == "" ||
        document.simple_form.email.value == "")
    {
        alert("Please fill out all fields before clicking submit!");
        return false;
    }
}


In this there is some logic that is not directly tied to the UI. So there is something we can test. But it’ll need a bit of a rework to make it testable

function isFormValid(formElement) {
    return (formElement.name.value != "" && formElement.email.value != "");
}

function validate() {
    if (!isFormValid(document.simple_form)) {
        alert("Please fill out all fields before clicking submit!");
        return false;
    }
}


Now we have a testable function isFormValid. It’s an example of separating the logic from the UI and the DOM interaction. There is still a DOM element being used but that’s fine as it is easy to create or perhaps mock in writing the test.

Code not worth testing

$(‘.button).click(function() {
  $(‘#my_quote’).css(‘background-color’, ‘red’);
}


This code is still testable despite using some jquery magic. It’s easy to mock out jquery or fake events and DOM enough to test it. Do not test this code. There is no real logic in there and it’s heavily tied to the UI interaction. This may mean a lot of the Javascript you’re writing does not have tests and that’s okay. Interactions like this are still best tested manually and if they fail in a harmful way will be obvious to anyone using the system. Logic errors however can be much harder to spot through manual testing.

Testable closures

function passwordCheckClosure(password) {
  return function(comparePassword) {
    return comparePassword === password;
  }
}


I love closures and closures like this are still really easy to test. Just as I would still expect you to create private methods and properties when doing TDD in C++ or Java. In Javascript I would still expect you to write closures to help build your code into clear abstract interfaces. But as with private methods and constructors you need to avoid hiding everything in closures.

Untestable closures

function validate() {
    function isFormValid(formElement) {
        return (formElement.name.value != "" &&
            formElement.email.value != "");
    }

    if (!isFormValid(document.simple_form)) {
        alert("Please fill out all fields before clicking submit!");
        return false;
    }
}


This is just a slight variation on our form valid check above. But now we cannot access isFormValid to test it separate to the validate method as a whole.

 Dependency injection with a closure

// formElenment - jquery reference to the form object
// alertMethod - alert on the browser. something else for console or tests
function attachFormValidator(formElement, alertMethod) {
    function isFormValid() {
        return (formElement.find(‘#name’).val() != "" &&
            formElement.find(‘#email’).val() != "");
    }
    formElement.submit(function(e) {
        if (!isFormValid()) {
          alert("Please fill out all fields before clicking submit!");
          e.preventDefault();
        }
      }
    );
}


This may seem harder to test. We've introduced expections that we’re using jquery and put everything within a function that does not return anything. But it’s actually very testable since we can easily mock out all the objects that we send in and trigger and test those actions through those mocks. Because objects are cheap and easy to construct that means it’s cheap and easy to mock things out.

Next time
Running tests with Jasmine and your web browser

This is part of a series I'm writing for Agile+ on Google+ so you can follow as I post them there

Comments

Popular posts from this blog

RestFixture

So most of the tests I'm writing now in Fitnesse are using RestFixture . Being able to do all this black box style testing has helped me get a lot of tests up and running without having to change the existing code base. Now I've taken a step future with my own little fork  so I can use scenarios and build nice BDD style scripts. But first I want to give me own quick guide to using RestFixture Step 1: Installing You can dive straight in by grabbing the latest jar files for RestFixture here  https://github.com/smartrics/RestFixture/downloads If you know what you're doing can get the nodep version to work nicely along side other libraries you may be including in Fitnesse. But I grabbed the 'full' version and unzipped it into a RestFixture folder alongside my FitNesseRoot folder. Step 2: Write your first test I took advantage of the built in Fitnesse api as a basic test and wrote a page called RestFixture with the following contents !define TEST_SYSTEM {slim} !

A brief introduction

And then I'll get into my first rant. I'm some guy who thinks about stuff. Stuff you probably don't care about but I'm going to tell you anyway! Now I don't think I'm going to cure cancer or create world peace but it'd be nice if I could make the world a little better. Stuff I'd like to talk about will focus on: Games I've always been a game player and am fascinated in how one designs a game. Yes it's mostly computer games these days and even then it's mostly consumed by World of Warcraft . Shut-up you in the back! We all have our vices and I'll avoid sniggering at your hentai collection if you leave my level 80 mage alone. Programming Only 2 years ago I was introduced to this weird concept of Test Driven Developmen t and the broader concept of Agile . Programming has been part of my life since I was eight. When I haven't been doing it professionally I've found myself doing it more in my free time. So it's nice that after 20+