Testing against Azure Table Storage with Node.JS, Mocha and Sinon

If, like me, you wanted to be able to write a Node.js app and use Azure Table Storage but also wanted to be able to effectively test your app without actually connecting to Azure, then here’s how!

Note: This article assumes you have a grasp of node, how to run node tasks and how to install node packages.

The App

First of all, allow me to direct you to the sample application on GitHub that we’ll be using for this article. It’s a simple console application that simply:

  • Creates a new table service instance
  • Writes a new entity to the table
  • Reads the same entity back from the table

It also contains a full test suite that examines and verifies the use of these three operations. The great thing is, the test suite does not connect to Azure! It simply verifies that the correct calls were made and stubs out everything else, which makes your tests reliable, fast and robust.

The main script is index.js which actually does the work, and the test suite is located in spec/azureSpec.js. *To run the app, simply execute *npm start from the console, and npm test to run the tests.

You don’t need to run the app, nor even have an Azure storage account to run the tests and to follow the article, but in case you do have an account and want to run the app itself (which actually does connect to Azure and read/write data), then you’ll need to add a configuration file to the config folder containing your Azure account details. To do this, create a file called ‘default.json’ that looks like the following:

The Packages

The main npm packages at play here are the following. There are others, but these are the primary ones that are involved with accomplishing what we need to with regards to this article:

azure-storage: Not strictly used as part of the test suite, but this is the API for working with Azure Storage (tables, blobs and queues). This is what we want to mock when running our tests

mocha: The test runner – this is what executes our tests and displays the results

chai: The assertion library – this is what allows us to verify the results, to prove that 1 + 1 = 2, or that a specific method was called by the test subject

sinon: The mocking/stubbing library – this allows us to replace methods and objects with fake ones, and be able to verify operations that act on them

sinon-chai: A sort of ‘glue’ between sinon and chai. It adds some helpers that make writing assertions on stubs and mocks a bit more friendly

proxyquire: Allows us to replace modules with other modules when we do ‘require’ inside a test subject – useful for swapping out the real azure-storage library with our own fake one!

The Tests

Let’s get to it. I’ve put all my tests for this into one file called ‘azureSpec.js’ inside my ‘spec’ folder, and my npm test command is set to mocha spec/ –recursive, just so that it’ll run all my tests in all my sub-folders in case I decide to add more later. By default Mocha expects your test file names to end with ‘Spec’ (as in ‘azureSpec.js’) so if you find it’s randomly not picking up a test suite, check your file names.

Setting up

First, a bit of set up inside the test file to configure all the packages we’re using. Most of them are just standard requires, but there’s a couple of interesting points.

var chai = require('chai');  
var sinon = require('sinon');  
var sinonChai = require('sinon-chai');  
var proxyquire = require('proxyquire').noCallThru(); var azure = require('azure-storage');  
var expect = chai.expect; chai.use(sinonChai);  

Everything is included that we need in order to assert condititions using Chai, create stubs with Sinon and mock out other requires with proxyquire. A couple of things to note are:

  • I’ve set proxyquire’s noCallThru() flag, which tells it not to call into base module methods
  • I’ve included sinon-chai, which contains some helpers with asserting method calls and whatnot, and then wired it up to chai on line 8 using chai.use(sinonChai). This will make it very easy later when we come to verify that calls to methods were made and with the correct arguments

Creating Stubs

The next thing to do is start creating our stubs. Looking at our test subject, i.e. the module that we’re testing, there are two things we need to stub out: the azure library, and our custom configuration file (the uuid module is fine since all that does is create some Guids for us):

var azure = require('azure-storage');  
var config = require('config').get('azure');  
var uuid = require('node-uuid');  
var tableService = azure.createTableService(config.accountName, config.accountKey);  
var entityGen = azure.TableUtilities.entityGenerator;  

As you can see, we use the azure package to create a table service instance, which we use to interact with Azure Storage. We need to swap this instance out with something we can control as part of the test and stop it from trying to connect to actual Azure. We also need to stub out the config file, mainly because I realised that if you don’t create one for this demo (which you might not, seeing as the configuration is not under source control) then the test will break. Besides, it’s easy to do.

Stubbing out the configuration looks like this. We create an object with a ‘get’ stub on it (representing the ‘get’ method) and have it just return an empty configuration object.

var config = {  
    get: sinon.stub().returns({ accountName: '', accountKey: '' }) };

Next, we need to stub out the table service type. createTableService returns an object that has various methods on it for retrieving and updating data, so let’s stub out the three methods we need that our module works: createTableIfNotExists, insertEntity and retrieveEntity:

var tableServiceStub = {  
    createTableIfNotExists: sinon.stub().callsArgWith(1, null, null),
    insertEntity: sinon.stub().callsArgWith(2, null, null), 
    retrieveEntity: sinon.stub().callsArgWith(3, null, null) };

Here we create a sinon stub for each method that the module will call, except this time we say “when insertEntity is called, call the function at argument position 2 with a null and another null as arguments”. Why do we do this?

Look at the signature for insertEntity:

tableService.insertEntity(tableName, entity, callback)

It takes a table name, the entity to update and a callback for when it has finished. So if we get our stub to call the function at argument 2, we’re just telling it to return a response straight away, simulating what Azure would have done out in the wild. We’ve set the return arguments to null for now, but we’ll come back to that later. The other two methods, createTableIfNotExists and retrieveEntity have been set up exactly the same way, except with a different argument number to reflect the position that the callback appears in the signature.

Finally, let’s stub out the azure object:

var azureStub = {  
    createTableService: sinon.stub().returns(tableServiceStub), 
    TableUtilities: { entityGenerator: azure.TableUtilities.entityGenerator } };

The trick here is that we’re telling createTableService to return the stub that we created in the previous step. So now we have a complete chain of stubs for Azure, and actual Azure should not be touched. We also include the existing entity generator utility straight out of the azure package, as our module will be making use of that.

Setting up Proxyquire

Proxyquire is a package that helps us test modules in isolation by supplying the module as required when the test subject calls ‘require’. This is how we can tell our test subject to use our azure module instead of the actual azure module, without actually changing our test subject:

proxyquire('../index.js', { 'azure-storage': azureStub, 'config': config });

The first argument is the module to require i.e. our test subject, and the second argument is an object hash containing the modules we want to replace. Note that the object keys are just the same name as required by the test subject.

Now, including this snippet of code has actually executed the module with our stubbed out modules. This means that my test subject has effectively executed. In your case, your test subject might be a class or function that you have to execute or call methods on in order to do anything, as in:

var subject = proxyquire('../index.js', {  
    'azure-storage': azureStub, 
    'config': config }); 

subject.run();  

Authoring the tests

At this point, the test has been executed and hopefully hasn’t produced any errors. So how can we verify what happened?

Line 11 of the example project inside index.js has a call to createTableIfNotExists, so let’s make sure that was done:

// index.js tableService.createTableIfNotExists('TestData', function(err, result) { ... } // azureSpec.js 

it('creates the table', function() {  
   expect(tableServiceStub.createTableIfNotExists).to.have.been.calledWith('TestData'); });

The syntax with sinon, chai and sinon-chai makes reading the test very self-explanatory. Here we simply verify that createTableIfNotExists was called with the argument ‘TestData’. If not, an exception will be thrown by the test runner and reported.

The next thing the test subject does is insert a new entity:

var id = uuid.v4();  
var entity = {  
   PartitionKey: entityGen.String('row'), 
   RowKey: entityGen.String(id), 
   message: entityGen.String('This is another row in the table') 
}; 

tableService.insertEntity('TestData', entity, function(err, result) { ... }  

Here we can test a few things; that the call to retrieveEntity was made, that the partition key was correct and that it had an id value for the row key. Here’s the test (inside its own ‘describe’ block):

var generatedId; // Next test - make sure it inserted the right entity 

describe('the insert entity operation', function() {  
   var insertedEntity = tableServiceStub.insertEntity.args[0][1]; // Store the id of the entity that was created, so that we can test that we retrieved it again later 

generatedId = insertedEntity.RowKey._; it('is called', function() {  
    expect(tableServiceStub.insertEntity).to.have.been.calledWith('TestData'); }); 

it('has the right partition key', function() { expect(insertedEntity.PartitionKey._).to.equal('row'); }); 

it('has a row key', function() { expect(insertedEntity.RowKey._).to.be.ok; }); });  

This is much like the earlier test, except it makes use of some additional Chai assert methods like ‘equal’ and ‘to.be.ok’. One thing I do here is to record the ID that the entity was given, so that I can verify the same entity was retrieved later. I can do this by retrieving the arguments that the stub was called with using the args collection on the stub, to get a hold of the entity object that the test subject created.

Finally, the test subject retrieves the entity it just created, with:

tableService.retrieveEntity('TestData', 'row', id, function(err, result) { ... }  

So let’s test that it did that:

describe('the retrieve entity operation', function() {  
   it('gets the correct entity', function() {

expect(tableServiceStub.retrieveEntity).to.have.been.calledWith('TestData', 'row', generatedId);  
   }); 
});

Exactly the same as before, except with different arguments. I’ve also verified it with the ID that the entity was created with, so I can make sure that the same entity was retrieved again.

Summary

Hopefully this has given you some insight into how to write test subjects that can use fairly complex libraries in practise, but can be stubbed out for testing. Again for reference, the example project that accompanies this article can be found on Github: https://github.com/elkdanger/blog-azuretesting. Feel free to clone/modify/tweak!