tomorrows web, here today

Comparing Object in Javascript

Compare Objects in Javascript Cover

As you start writing unit-test you will undoubtedly discover the challenges of comparing object in Javascript. In this short article we will look at how to do object comparison in Javascript to make our unit tests easier to work with. We will take a look at one popular unit-testing framework, Mocha.js, but the lessons here can be applied to other frameworks like QUnit and JSTestDriver as well.

Lets begin by taking a look by considering a task we would like to create tests for.

The function above takes a string representing a range of years and returns an array of the individual years in that range. Pretty simple. Now lets write our first test for it:

The test above will always fail since assert.equals uses a simple comparision operator (==) to compare the two objects given to it. In our case it is two arrays, each with a different memory reference (memory address). Since the compare in javascript compare the memory addresses it will always return false. Try it by typing [] == [] in your console (Node.js console or browser console).

Lets try another function assert in Node.js offers us called assert.deepEqual().

This actually works well. The problem is that when things break you don’t get very good feedback on what went wrong. It will simply say: “AssertionError: converting a range”, which does not give us much to go on.
Screenshot of failed UnitTest in Mocha.js

Mocha.js like other unit-testing frameworks have a good string compare tool that shows the differences between two strings that are compared using assert.equal. We can use that to our advantage to generate a string from the object and compare them as strings. This will allow us to see the differences between two objects easily. This comes in very handy when you have large objects were you can immediately see why your unit test has failed.

Screenshot of string Comparison in Mocha.js

We can do it using the following code:

This works well, if you can be guranteed the order of keys in your hashes. In our case it is an array with keys 0, 1, 2. The order is guranteed since it is the nature of arrays. But the following test will fail since the order is different:

This fails because the resulting strings will have the properties in different order. To fix this we will use the following code:

(Find it on SnippetSky: http://www.snippetsky.com/snippets/5037d0879fcb0c0200000046)

To make sure the order of the keys does not matter, the above code sorts the keys first and then does a string compare based on the sorted keys. This means that doing the following will pass:

Recap

Use the code above when you are comparing objects and arrays. If the class of the object is important to you (for dates for example) compare the classes too using the instanceof operator in a separate test case.

Happy testing :).

Update 1: Improved assertObjectEqual to support an array of objects as well as just an array of primitives.
Update 2: Fixed problem with false positive reports due to a bug in the keys function.

  • http://twitter.com/Skipants Andrew Szczepanski

    Good stuff. If I remember correctly, Jasmine (my personal favourite when it comes to testing JS) also overrides deepEqual in order to get the same assert.equal functionality.

    • yagudaev

      Yeah Jasmin has something called Matchers, which are clever little function you can use to test results against. From what I can tell, it is very similar to Mocha.js, the only problem with Jasmin is that async testing is overly complicated. In Mocha it is very simple.

      I should also mention that there is a library called should.js for Node.js that can do equality testing as well (very similar to Jasmine’s Matchers) like this: ({ foo: ‘bar’ }).should.eql({ foo: ‘bar’ }). https://github.com/visionmedia/should.js/tree/#eql

  • Max

    How about _.isEqual() method of underscore library?

    • yagudaev

      It works great for getting a true or false value, but when you need to see the differences it provides no insight. The comparison function in the article is specifically for unit tests.

  • Nikola Stamatovic

    Hey,
    Sorting properties is just an additional for loop you don’t really need cause you can iterate object’s properties one by one, that means the iteration and comparison of the values will go much faster than converting every object to string and comparing strings. Comparing strings is very slow, because if they are the same length you iterate every character and compare it’s value. I’ve thought about this past few days and if you want you can check my solution: http://stamat.wordpress.com/2013/06/22/javascript-object-comparison/ I would really appreciate your opinion on the matter.

    • yagudaev

      I love your approach. It took me a few minutes to wrap my head around it, but I love the use of hasOwnPropertyOf to check if the other object has the property. It is brillant. You bring about a very good point about performance and unit tests that run slow are not very good.

      If you look again at my post, it was about making it easy to spot the differences when your unit tests fail. To make it really clear text comparison is best.

      Now, most of the time in a big test suite you will get that majority of the tests pass. So combining your approach with mine will bring the most benefits. In other words writing an assertDeepEquals function that first uses your approach to compare the objects. If the objects are not equal, then it will use my approach with converting them to strings so that a string comparison tool can be used to show the differences. That way you are both getting the performance and usability of both.