Data driven JavaScript tests using Jasmine
This post was published on April 27, 2016In my previous post I introduced Jasmine as a tool for testing JavaScript code. Now that I’ve had some more time to play around with it, combining it with Protractor for user interface-driven tests for one of my client’s websites, I’ve noticed that one feature was sorely missing: built-in support for data driven testing. All BDD tools (or tools that say they support BDD) that I have worked with so far, such as Cucumber, SpecFlow and JGiven, support the creation of data driven scenarios. However, Jasmine doesn’t, at least not as far as I have seen in the limited time I have been using it so far.
As I think data driven testing is key when creating maintainable and reusable scenarios, I fired up Google to check whether someone had already found a solution. From what I’ve read, there are (at least) two different ways to do data-driven testing with Jasmine. Let’s have a look at both.
Specifying your test data in an array variable
I found the first approach in the comments of this StackOverflow post. The comment submitted by peterhendrick suggests the use of a JSON file containing the test data. I slightly simplified this to use a simple array of key-value pairs and have the Jasmine spec loop through the array. You can simply populate this array any way you like, for example from an external .json file as suggested, but in any other way as well. In this example, I hard-coded it in the spec itself:
describe("Calculator (data driven tests with test data specified in array)", function() { var calc; var testdata = [{"x":1,"y":1,"sum":2},{"x":2,"y":3,"sum":5},{"x":4,"y":2,"sum":6}]; beforeEach(function() { calc = new Calculator(); }); for(var i in testdata) { it("should be able to add two numbers, using (" + testdata[i].x + "," + testdata[i].y + "," + testdata[i].sum + ")", function() { expect(calc.add(testdata[i].x, testdata[i].y)).toEqual(testdata[i].sum); }); }; });
I particularly like this example because it enables you to add the actual values used to the test output. You can see this when you run your spec:
Data driven testing with a custom using function
This blog post from JP Castro presents an alternative way to do data driven testing in Jasmine. His solution seemed easy enough for me to apply directly to my own specs. Let’s see what it looks like.
The basic idea behind his solution is to wrap each it block in a spec with a using block that passes the parameter values to the it block:
describe("Calculator (data driven tests with using() function)", function() { var calc; beforeEach(function() { calc = new Calculator(); }); using('parameters',[[1,1,2],[2,3,5],[4,2,6]], function(parameters){ it("should be able to add two numbers, using (" + parameters[0] + "," + parameters[1] + "," + parameters[2] + ")", function() { expect(calc.add(parameters[0],parameters[1])).toEqual(parameters[2]); }); }); });
The using function he presents is implemented as follows:
function using(name, values, func) { for(var i = 0, count = values.length; i < count; i++) { if(Object.prototype.toString.call(values[i]) !== '[Object Array]') { values[i] = [values[i]]; } func.apply(this,values[i]); } }
When we run the spec above, the output looks like this:
So, now we have two simple (and admittedly similar) workarounds for what I think is still a fundamental shortcoming in Jasmine. The code demonstrated in this blog post can be downloaded here.
"