Jest mock knex fn.now(), but keep rest of implementation - jestjs

I am writing tests for a service that uses knex, however, since the knex calls has several uses of knex.fn.now() my tests will produce varied results over time. I'm wondering if it's possible to mock/spy/hijack the inner calls to knex.fn.now() to something I can control, while letting the rest of the code stay in its 'real' implementation. I can only find examples of mocking knex completely which would make the purpose of my testing pointless.
So I'm wondering if it's possible to have jest listen for a specific function call and insert another value in it's stead.

You can mock Knex package by creating a folder __mocks__/knex/index.js.
Inside this file u can require the real knex implementation, change it, and export.
It should look something like this:
// __mocks__/knex/index.js
const knex = require('knex');
const fixedTime = new Date();
knex.fn.now = () => fixedTime;
module.exports = knex;

Related

Sinon not stubbing due to multiple test cases

GitHub Repo
When I run my test cases using mocha, sinon will set up the stubs based on the first app.js that gets called. Looking at other people having the same problems it looks like the problem is that when I require('../../../app') it is pulling in a cached version so it is using the same stubs as whatever was set up the first time I called it.
What I've tries in the beforeEach section on both test cases:
decache('../../../app'); app = require('../../../app')
Using Sinon Sandbox and restoring
that
delete require.cache[require.resolve('../../../app')]; app = require('../../../app')
Using mockery to reset the cache
I dont know if its calling the cached version of the requirement or if I'm not stubbing it out correctly.
Thanks in advance for any help that can be provided.
By default, modules are imported in a Singleton-type behaviour in Node e.g.
const app = require('./app');
app.someProperty = 'x';
If I require app again in another file after this, then you can expect someProperty to still be x because, as you have worked out, Node will cache the result and return the same one every-time.
In your case this is less an issue with Node, and more your usage of Sinon - when you stub something, the common practise is to restore the value back after the test is finished e.g.
const app = require('...');
before(() => sinon.stub(app,'someFunction'));
after(() => app.someFunction.restore());

"Global" module object in Node.js

I have a module for connecting to my DB and perform actions.
Then in my main script (app.js) I instantiate it like
var DBConn = require('./common/DBConn');
And from that script it works fine. But then I've got some other scripts that handle routes, and I want to perform some DB stuff on those, but if I use DBConn it returns an error saying "DBConn is not defined".
Then I can just instantiate another DBConn in these other js files, but this would mean I am creating a connection for each file, right? But I want these other scripts to use the DBConn object from the app.js, so that I'm not constantly establishing a connection to the DB and then closing it... (unless this is a good idea, but to me it makes more sense to have just one "global" object dealing with the connection over all the app and that's it).
(BTW: I'm using Express)
You want to require() your module in each file. Node will cache the module.
Typically, the context of a DB connection is abstracted away behind stores or repositories and your other modules interact with those. In cases where people are directly requiring modules like mongoose, they'll require mongoose everywhere but only call the connection code within their main application entry point (app.js/server.js/whatever).
https://nodejs.org/api/modules.html#modules_caching
Modules are cached after the first time they are loaded. This
means (among other things) that every call to require('foo') will get
exactly the same object returned, if it would resolve to the same
file.
Multiple calls to require('foo') may not cause the module code to be
executed multiple times. This is an important feature. With it,
"partially done" objects can be returned, thus allowing transitive
dependencies to be loaded even when they would cause cycles.
If you want to have a module execute code multiple times, then export
a function, and call that function.
You could use a singleton to solve this issue for you. Please remember however that singletons come with their own set of problems (a good discussuon on singletons can be found here What is so bad about singletons?).
That said once you take into consideration the pro's and cons of singletons they can be a fantastic solution to exactly this problem.
Example:
// database.js
var singleton = function singleton() {
this.DbConnection = {};
function setup(database, username, password) {
this.DbConnection = MakeDbConnection()
};
};
singleton.instance = null;
singleton.getInstance = function(){
if(this.instance === null){
this.instance = new singleton();
}
return this.instance;
};
module.exports = singleton.getInstance();
This can then be called elsewhere in your application like so...
// main.js
var db = require("./database");
db.setup('db', 'root', 'pass');
db.DbConnection();
Once you have called db.setup() the first time, the db connection will be available just with the following:
// elsewhere.js
var db = require("./database");
db.DbConnection();

Sinon - when to use spies/mocks/stubs or just plain assertions?

I'm trying to understand how Sinon is used properly in a node project. I have gone through examples, and the docs, but I'm still not getting it. I have setup a directory with the following structure to try and work through the various Sinon features and understand where they fit in
|--lib
|--index.js
|--test
|--test.js
index.js is
var myFuncs = {};
myFuncs.func1 = function () {
myFuncs.func2();
return 200;
};
myFuncs.func2 = function(data) {
};
module.exports = myFuncs;
test.js begins with the following
var assert = require('assert');
var sinon = require('sinon');
var myFuncs = require('../lib/index.js');
var spyFunc1 = sinon.spy(myFuncs.func1);
var spyFunc2 = sinon.spy(myFuncs.func2);
Admittedly this is very contrived, but as it stands I would want to test that any call to func1 causes func2 to be called, so I'd use
describe('Function 2', function(){
it('should be called by Function 1', function(){
myFuncs.func1();
assert(spyFunc2.calledOnce);
});
});
I would also want to test that func1 will return 200 so I could use
describe('Function 1', function(){
it('should return 200', function(){
assert.equal(myFuncs.func1(), 200);
});
});
but I have also seen examples where stubs are used in this sort of instance, such as
describe('Function 1', function(){
it('should return 200', function(){
var test = sinon.stub().returns(200);
assert.equal(myFuncs.func1(test), 200);
});
});
How are these different? What does the stub give that a simple assertion test doesn't?
What I am having the most trouble getting my head around is how these simple testing approaches would evolve once my program gets more complex. Say I start using mysql and add a new function
myFuncs.func3 = function(data, callback) {
connection.query('SELECT name FROM users WHERE name IN (?)', [data], function(err, rows) {
if (err) throw err;
names = _.pluck(rows, 'name');
return callback(null, names);
});
};
I know when it comes to databases some advise having a test db for this purpose, but my end-goal might be a db with many tables, and it could be messy to duplicate this for testing. I have seen references to mocking a db with sinon, and tried following this answer but I can't figure out what's the best approach.
You have asked so many different questions on one post... I will try to sort out.
Testing myFuncs with two functions.
Sinon is a mocking library with wide features. "Mocking" means you are supposed to replace some part of what is going to be tested with mocks or stubs. There is a good article among Sinon documentation which describes the difference well.
When you created a spy in this case...
var spyFunc1 = sinon.spy(myFuncs.func1);
var spyFunc2 = sinon.spy(myFuncs.func2);
...you've just created a watcher. myFuncs.func1 and myFuncs.func2 will be substituted with a spy-function, but it will be used to record the calling arguments and call real function after that. This is a possible scenario, but mind that all possibly complicated logic of myFuncs.func1/func2 will run after being called in the test (ex.: database query).
2.1. The describe('Function 1', ...) test suite looks too contrived to me.
It is not obvious which question you actually mean.
A function that returns a constant value is not a real life example.. In most cases there will be some parameters and the function under test will implement some algorithm of transmuting the input arguments. So in your test you're going to implement the same algorithm partly to check that the function works correctly. That is where TDD comes in place, which actually supposes you start implementation from a test and take parts of unit test code to implement the method being tested.
2.2. Stub. The second version of unit test looks useless in the given example. func1 is not accepting any parameter.
var test = sinon.stub().returns(200);
assert.equal(myFuncs.func1(test), 200);
Even if you replace the return part with 100 the test will run successfully.
The one that makes sense is, for example, replacing func2 with a stub to avoid heavy calculation/remote request (DB query, http or other API request) being launched in a test.
myFuncs.func2 = sinon.spy();
assert.equal(myFuncs.func1(test), 200);
assert(myFuncs.func2.calledOnce);
The basic rule for unit testing is that unit test should be kept as simple as possible, providing check for as smallest possible fragment of code. In this test func1 is being tested so we can neglect the logic of func2. Which should be tested in another unit test.
Mind that doing the following attempt is useless:
myFuncs.func1 = sinon.stub().returns(200);
assert.equal(myFuncs.func1(test), 200);
Because in this case you masked the real func1 logic with a stub and you're actually testing sinon.stub().return(). Believe me it works well! :D
Mocking database queries.
Mocking a database has always been a hurdle. I could provide some advises.
3.1. Have well fragmented environment. Even for a small project there better exist a development, stage and production completely independent environments. Including databases. Which means you have an automated way of DB creation: scripts or ORM.
In this scenario you will be easily maintaining test DB in your test engine using before()/beforeEach() to have a clean structure for your tests.
3.2. Have well fragmented code. There'd better exist several layers. The lowest (DAL) should be separated from business logic. In this case you will write code for business class, simply mocking DAL. To test DAL you can have the approach you mentioned (sinon.mock the whole module) or some specific libraries (ex.: replace db engine with SQLite for tests as described here)
Conclusion. "how these simple testing approaches would evolve once my program gets more complex".
It is hard to maintain unit tests unless you develop your application with tests in mind and, thus, well fragmented. Stick to the main rule - keep each unit test as small as possible. Otherwise you're right, it will eventually get messy. Because the constantly evolving logic of your application will be involved in your test code.

Node.js requiring a script but not running it

In Node.js, when you do
var otherscript = require('otherscript');
it runs the script upon the require
I am wondering if there is a way to "require" a script without running it, so that you can run it later when you want to.
Is there any good reason why not?
If you can edit the 'otherscript' (no one else is using that script) then you can simply enclose the whole code inside a function and add it to exports.
Example:
otherscript:
module.exports = function(){
//original code goes here
};
Then use as:
var otherscript = require('otherscript');
var obj = otherscript();
When you require a file or module, the return of that file/module is cached. In other words, it is really only executed once, and subsequent calls to require() of that file/module will only return a reference to the exact same object.
A common example of this is the Mongoose package, where calling require('mongoose') will return an instance of mongoose, on which you can call connect() to connect to the database. Calling require('mongoose') again in a different part of your program will return the same instance with the same database connection made available.

Mongoose connection/models: Need to always run on open?

I am using Mongoose 3 and the most obvious way to connect to database is
conn = mongoose.createConnection(...)
conn.on("open", ...)
Question is, do I need to define all my models in the open callback? If that is so, I will have to create a initMongoose.coffee that looks like
# initMongoose.coffee
mongoose = require "mongoose"
module.exports = mongoose.createConnection ...
# modelExample.coffee
conn = require "./initDatabase"
conn.on "open", ->
... define model?
modeule.exports = model # I think this does not work?
I think I read somewhere in Node docs that modules cannot be defined in a callback like that?
Since I am only using 1 connection, I think I can use
mongoose.connect ...
Which doesnt accepts any callbacks so I suppose is synchronous? Can I define all my models and thus queries right after connect()? It works at the moment, but it might be because its fast enough.
Mongoose buffers up commands until it is finished connecting, so you can treat it like it's synchronous and define your models and start using the library whenever you want; only once you want to start actually inserting or retrieving data do you need to make the connection.

Resources