unit testing nested objects in javascript/node - javascript

I have an object called NetFlowStorage that contains methods to access a specific elasticsearch index. My constructor looks like:
function NetFlowStorage() {
this.host = 'localhost:9200';
this.shards = '4';
this.replicas = '0';
this.index_name = 'flow_track2';
this.client = null;
}
Inside of the object I have a method called connect which, when called, will make the connection and store the elasticsearch client object in the this.client property (if there isn't one already there). This way all of the object methods can get access to the elasticsearch client by using this.client
First question, is this an appropriate pattern? If not, what is preferable?
Second question (and the one that drove me here), how would I mock calls to things like this.client.index({}) I'm just starting to mess around with unit testing and mocks under node/js so I don't really have a preference in terms of framework (currently using mocha/chai/sinon)
Full code is here if you want to see in more detail.

For something like this I would use dependency injection.
You want to decouple the NetFlowStorage class from the actual elasticsearch client:
function NetFlowStorage(esClient) {
this.host = 'localhost:9200';
this.shards = '4';
this.replicas = '0';
this.index_name = 'flow_track2';
// if you don't wanna share connections across several instances
// you can instantiate the client here otherwise you can pass the
// client instance
this.client = esClient; // or new esClient({ host: this.host })
}
This way you won't even need the elasticsearch as part of the node module and even share a connection across more than one instance (or not?)
This decoupling will also make it easier to mock the esClient as you would inject the mock elasticsearch client in the test itself.

I think that you should pass a config object and a connection object to the method.
So if you would use Jasmine for testing for example you could pass a spy
var client = {index:function(){}}
spyOn(client, 'index');
....
expect(client.index)toHaveBeenCalled();
and to pass it at some point with injection or a singleton to the SUT

Related

namespacing a JavaScript class but retaining the same 'this'

I'm building a fairly large node.js client library and I'd like to be able to 'namespace' portions of it to keep it more organized. For example:
var client = new Client(config);
client.activities.get(activityId, function(activity) {
...
});
...
client.user.get(userId, function(user) {
...
});
I'm currently trying to do something like this in the module:
function Client(config) {
this.config = config;
}
Client.prototype.activities = require('./activities');
Client.prototype.user = require('./user');
module.exports = Client;
but when 'get' is called in the activities 'submodule', the "this" is for the module, of course, and not the outer Client function. Basically, both of the submodules need access to the outer configuration information ('config' in this example). What is the best practice around doing this in node.js?
I think a modeling issue with the plan you have is that new X() copies each property reference of X.prototype to the new item; for instance, X.myFunction is the exact same reference as X.prototype.myFunction; but does NOT create a new copy of myFunction.
It sounds like if activities is a part of a Client (the same way StreetAddress might be), you actually want activities to be a Class, not a module, and for Client to create a new instance of it when it's constructed. That's not really something that prototype is useful for. If I'm wrong, maybe you could show an example of a basic operation activities would be used for.

Is it possible to spy on or mock the value of a "behind-the-scenes" variable?

Let's say I have code that modifies a variable which is not exposed to the user like this:
var model;
module.exports = {
doSomething: function() {
...
//at some point in the code, modify model
if(/* something happened */) {
model = '123';
},
doSomethingElse: function() {
//use model in some way
}
}
};
If I later want to write a unit test to make sure that model was updated, but I do not have a getter for it, how can I test this? Is this possible to do with Karma/Jasmine/Sinon.js?
It is impossible to check the model value directly because it's hidden in a closure.
You can still write tests for it though: Your "model" will make doSomethingElse behave differently. You can verify that it matches your expectations after calling doSomething. This way, you are also free refactor the internals of your module without changing the test cases.
In general, testing private methods or properties is an antipattern. By making aspects of your implementation private, you're explicitly creating the freedom to change how those implementation details work in the future without changing your public API.
Therefore, in an ideal world, you should not (and in this case, you cannot) test the model value.
That said, we don't always live in an ideal world. So, there are some workarounds that you might consider if you really, really must test private properties and methods.
First, you could look for an environment variable, and export additional properties (by attaching them to the exports).
var model;
module.exports = {
...
}
if(process.env.ENV === 'TEST') {
module.exports.model = model;
}
Second, you can use conventions instead of making things completely private. For example, a common convention is to prefix private entities with _ to signify that they are not part of the public API. This can have varied levels of effectiveness depending on the audience that will consume your API.
Third, you could create accessors for your private variables, and check for the presence of a testing environment in some way (perhaps a global variable, an environment variable, or a variable injected into your module upon instantiation) that only allows access when the test environment is detected.
Fourth, you could allow an "inspector" object to be injected into your module (this object would only be present during testing). I have used this pattern with some success.
module.exports = function(spies) {
...
spies = spies || {};
var model = spies.model;
...
}
...
// instantiate the module in the test
var spies = {};
var mock = new Module(spies);
// do a thing
expect(spies.model).to.eql("foo");
But really, you should reconsider your testing strategy and design.

Node.js JavaScript how to access oject data in asynchronous event handlers as "socket.on" in TCP servers?

I'm trying to find the right strategy to access a existing object from within my events handler, and wonder if the bypass I propose here after is a good option or not.
In following sample, I have a class to built a simple TCPServer. After server creation time, when a new tcpclient arrives, within "ConnectAction" function I need to access "devName" variable to find which server instance is concerned. As a result "DevName" cannot be global and needs to be specific to current instantiation of my TCPServer object.
------ Extract from my code --------
// TCPserver Object Class
TcpServer = function (devName, port) {
// event handler executed each time a new TCP client connect to the server
ConnectAction = function (socket) {
// for ech new client we create a new device and store it within server object
device = new TCPClient (devName, socket);
};
this.server = net.createServer(ConnectAction);
this.server.listen(port);
return this;
}
Server1 = new TcpServer ("My First Server", 8080):
Server2 = new TcpServer ("My Second Server", 8081):
In other script languages that I used in the past, it was possible to add an extra argument to event handlers. But in NODE.JS something like server=net.createServer(ConnectAction SomeExtraHandler); does not work.
The only bypass I find is to leverage arguments passed at object construction time.
When the event handler code is embedded within the object border as in this example; then while even handlers are called outside of TCPserver object context "this not defined", handlers can still leverage parameters that where passed at object creation time. In this case "devName".
My question: is my bypass safe ? is there a better approach to solve this issue ?
The full code of my sample is available at: http://www.fridu.org/download/private/TcpServer.js
If anyone has a better strategy, I would be more than happy to learn about it. In my real application, I should have ten or so differences server instances, with few hundred of clients connected to each of them. Which raise a second question, will my object coding approach in node.js support the load ?
My question: is my bypass safe?
Yes, it's totally safe. Using closures is the javascript way to solve this problem, you don't need to explicitly pass extra arguments around.
Notice however that ConnectAction, ListenAction and device should not be global variables, they are instance-specific and would better be scoped to the constructor as well; else they might interfere with other tcp servers.
is there a better approach to solve this issue?
There is a different, although not necessarily better, way: put the devName as a property on your object. The connectAction is called within the context of your server, so you can simply access it there - at least that would be the case if your TcpServer would inherit from the net.Server. As you have a wrapper around your server, you could do something like this:
// event handler executed each time a new TCP client connect to the server
function ConnectAction(socket) {
// for ech new client we create a new device and store it within tcp server object
this.tcp.device = new TCPClient (this.tco.devName, socket);
}
function TcpServer(devName, port) {
this.devName = devName;
this.server = net.createServer(ConnectAction);
this.server.tcp = this;
this.server.listen(port);
}
It should be perfectly fine to use devName as you are already doing. However, if you want or need to move your ConnectAction function outside your TcpServer implementation for some reason, you could use bind() to accomplish what you're trying to do.
Relevant bit from the docs:
bind() also accepts leading default arguments to provide to the target
function when the bound function is called.
What this means in your case is that you can create a bound version of ConnectAction which already has devName set as one of its arguments. It would look something like this:
ConnectAction = function (devName, socket) {
// for ech new client we create a new device and store it within server object
device = new TCPClient (devName, socket);
};
var boundConnectAction = ConnectAction.bind(undefined, devName)
this.server = net.createServer(boundConnectAction);
In that code, boundConnectAction will still be called from createServer as normal (boundConnectAction(socket)) but, because it's bound to ConnectAction with a default argument for devName, it will pass on that call as if it was ConnectAction(devName, socket).
Note: bind()'s first argument is used as this in the bound function. Since ConnectAction doesn't look like its intended to be an object/class instance method, I just passed undefined, but you might want to pass something else depending on your use case.
As to your other question regarding node handling the load, I'd suggest splitting out your ten or so server instances in to separate node processes so that the load is better distributed. Take a look at child_process or possibly cluster to help out with that.

How to organize models in a node.js website?

I have just started experimenting with building a website using node.js, and I am encountering an issue when organizing the models of my project.
All the real world examples I have found on the Internet are using Mongoose. This library allows you to define your models in a static way. So you can write this:
// models/foo.js
module.exports = require('mongoose').model('Foo', ...);
// app.js
mongoose.connect(...);
// some_controller_1.js
var Foo = require('./models/foo');
Foo.find(...);
// some_controller_2.js
var Foo = require('./models/foo');
Foo.find(...);
But since I don't want to use MongoDB, I need another ORM. And all the other ORMs I have found don't allow this. You first need to create an instance, and then only you can register your models. Also they don't seem to allow access to the list of registered models.
So I tried doing this:
// models/user.js
var registrations = [];
module.exports = function(sequelize) {
var result = null;
registrations.forEach(function(elem) {
if (elem.db == sequelize)
result = elem.value;
});
if (result) return result;
// data definition
var user = sequelize.define("User", ...);
registrations.push({ db: sequelize, value: user });
return user;
};
Which I can use this like:
// some_controller_1.js
var Foo = require('./models/foo')(app.get('database'));
Foo.find(...); // using Foo
But these small header and footer that I have to write on every single model file are a bit annoying and directly violate the "don't repeat youself" principle. Also, while not a huge issue, this is kind of a memory leak since the "sequelize" object will never be freed.
Is there a better way to do, which I didn't think about?
You can find an article about handling models with sequelize here: http://sequelizejs.com/articles/express#the-application
You basically just create a models/index.js as described here: http://sequelizejs.com/articles/express#block-3-line-0
Afterwards you just put your model definitions within files in the models folder as pointed out here: http://sequelizejs.com/articles/express#block-4-line-0

How can i use sinon to stub functions for neo4j Thingdom module

I am having some issues writing some unit tests where i would like to stub out the functionality of the neo4j Thingdom module.
After a few hours of failed attempts i have been searching around the web and the only point of reference i found was a sample project which used to sinon.createStubInstance(neo4j.GraphDatabase); to stub out the entire object. For me, and becuase this seemed to a be a throw away project i wanted a more fine grained approach so i can test that for instance as the Thingdom API outlines when saving a node you create it (non persisted) persist it and then you can index it if you wish which are three calls and could be outlined in multiple specific tests, which i am not sure can be achieved with the createStubInstance setup (i.e. found out if a function was called once).
Example "create node" function (this is just to illustrate the function, i am trying to build it out using the tests)
User.create = function(data, next){
var node = db.createNode(data);
node.save(function(err, node){
next(null,node);
});
};
I am able to stub functions of the top level object (neo4j.GraphDatabase) so this works:
it('should create a node for persistence', function(){
var stub = sinon.stub(neo4j.GraphDatabase.prototype, 'createNode');
User.create({}, res);
stub.calledOnce.should.be.ok;
stub.restore();
});
The issue comes with the next set of test i wish to run which tests if the call to persist the node to the database is called (the node,save) method:
I am not sure if this is possible or it can be achieved but i have tried several variations of the stub and non seem to work (on neo4j.Node, neo4j.Node.prototype) and they all come back with varying errors such as can't wrap undefined etc. and this is probably due to the createNode function generating the node and not my code directly.
Is there something i am glaringly doing wrong, am i missing the trick or can you just not do this? if not what are the best tactics to deal with stuff like this?
A possible solution is to return a stubbed or mocked object, giving you control on what happens after the node is created:
it('should create a node for persistence and call save', function () {
var stubbedNode = {
save: sinon.stub().yields(undefined, stubbedNode)
};
var stub = sinon.stub(neo4j.GraphDatabase.prototype, 'createNode').returns(stubbedNode);
User.create({}, res);
stub.calledOnce.should.be.ok;
stub.restore();
stubbedNode.save.calledOnce.should.be.ok;
});
We couldn't do it directly, the way the module is setup it doesn't work to well with Sinon. What we are doing is simply abstracting the module away and wrapping it in a simple facade/adapter which we are able to stub on our unit tests.
As we are not doing anything bar calling the neo4j module in that class we are integration (and will validate when regression testing) testing that part to make sure we are hitting the neo4j database.

Categories

Resources