I need to assert whether a constructor was called using sinon. Below is how I can create a spy.
let nodeStub: any;
nodeStub = this.createStubInstance("node");
But how can I verify that this constructor was called with the relevant parameters? Below is how the constructor is actually called.
node = new node("test",2);
Any help would be much appreciated.
Below is the code I have.
import {Node} from 'node-sdk-js-browser';
export class MessageBroker {
private node: Node;
constructor(url: string, connectionParams: IConnectionParams) {
this.node = new Node(url, this.mqttOptions, this.messageReceivedCallBack);
}
}
Given the following code myClient.js:
const Foo = require('Foo');
module.exports = {
doIt: () => {
const f = new Foo("bar");
f.doSomething();
}
}
You can write a test like this:
const sandbox = sinon.sandbox.create();
const fooStub = {
doSomething: sandbox.spy(),
}
const constructorStub = sandbox.stub().returns(fooStub);
const FooInitializer = sandbox.stub({}, 'constructor').callsFake(constructorStub);
// I use proxyquire to mock dependencies. Substitute in whatever you use here.
const client2 = proxyquire('./myClient', {
'Foo': FooInitializer,
});
client2.doIt();
assert(constructorStub.calledWith("bar"));
assert(fooStub.doSomething.called);
//module.js
var Node = require('node-sdk-js-browser').Node;
function MessageBroker(url) {
this.node = new Node(url, 'foo', 'bar');
}
module.exports.MessageBroker = MessageBroker;
//module.test.js
var sinon = require('sinon');
var rewire = require('rewire');
var myModule = require('./module');
var MessageBroker = myModule.MessageBroker;
require('should');
require('should-sinon');
describe('module.test', function () {
describe('MessageBroker', function () {
it('constructor', function () {
var spy = sinon.spy();
var nodeSdkMock = {
Node: spy
};
var revert = myModule.__set__('node-sdk-js-browser', nodeSdkMock);
new MessageBroker('url');
spy.should.be.calledWith('url', 'foo', 'bar');
revert();
});
});
});
Related
I'm unit testing a method in fileA.js that requires a new class instance from fileB.js with success.
The problem is that I get success, as expected but this specific test hangs and I don't get results from istanbul.
Yes, I have already added --exit flag. This only happens if I run this test... Why does it hang?
This is the method in fileA.js:
global.mapperObj = {};
const opts = config.opts
(...)
async function startServices() {
const data = await getData();
Object.keys(data).forEach(function(key) {
mapperObj[key] = new ClassInFileB(key, data[key], opts);
mapperArray.push(key);
});
}
The class in fileB.js:
const npmPool = require('npmPackage');
class ClassInFileB{
constructor(ip, port, opts) {
this.classPool = npmPool.createPool(ip, port, opts);
}
(...)
// other class methods
}
And the test for that method:
const rewire = require('rewire');
const fileA = rewire(`path/to/fileA`);
const ClassInFileB = require(`path/to/fileB`);
describe('Testing startServices() function', function () {
it('It should not throw errors', async function () {
let result;
let error = false;
global.mapperArray = [];
try {
function getDataMock() {
return { '0.0.0.1': 'thisIsSomething'};
}
fileA.__set__('getData', getDataMock);
// Create a stub instance to ClassInFileB class avoiding the constructor
sinon.createStubInstance(ClassInFileB);
result = await fileA.startServices();
} catch (err) {
error = err;
}
expect(error).to.be.false;
});
I am trying to write a unit test for the class in the example below.
const DependencyClass = require('../../../../Dependency/src/index').DependencyClass;
const string = 'test';
class FirstClass {
async getResult() {
const dependency = new DependencyClass();
const result = dependency.getResult(string);
return result;
}
}
module.exports = {
FirstClass
};
I am trying to stub the getResult() method of the DependencyClass class so it returns a predefined value when called from my unit tests but cant figure out how to do it.
const FirstClass = require('../../lib/FirstClass ').FirstClass;
describe('FirstClass.js', function() {
describe('getResult()', function() {
it('throws an exception if the result is not returned', async function() {
const firstClass = new FirstClass();
sinon.replace(firstClass.getResult, 'DependencyClass.getResult', function() {
const fakeResult =
[
'test1',
'test2'
];
return fakeResult;
});
const expectedResult =
[
'test1',
'test2'
];
const result = await firstClass.getResult();
expect(result).to.deep.eq(expectedResult);
});
});
});
afterEach(function() {
sinon.restore();
});
I understand that DependencyClass.getResult is not a property of the firstClass.getResult object but I am struggling to understand how sinon should be used in this context.
If you want to stub method getResult() from class DependencyClass, then you need to create stub from it: sinon.stub(DependencyClass.prototype, 'getResult');.
Here the complete example.
Note: I remove all async await, because it is unnecessary for this simple example.
File DependencyClass.js
// #file DependencyClass.js
class DependencyClass {
getResult() {
return 'xxx';
}
}
module.exports = { DependencyClass };
File FirstClass.js
// #file FirstClass.js
const { DependencyClass } = require('./DependencyClass.js');
const string = 'test';
class FirstClass {
getResult() {
const dependency = new DependencyClass();
return dependency.getResult(string);
}
}
module.exports = { FirstClass };
Test spec file
// #file stackoverflow.spec.js
const sinon = require('sinon');
const { expect } = require('chai');
const { DependencyClass } = require('./DependencyClass');
const { FirstClass } = require('./FirstClass');
describe('FirstClass.js', function () {
describe('getResult()', function () {
it('throws an exception if the result is not returned', function () {
// Create fake response.
const fakeResult = ['test1', 'test2'];
// Create stub DependencyClass method getResult().
const stubDependencyGetResult = sinon.stub(DependencyClass.prototype, 'getResult');
stubDependencyGetResult.returns(fakeResult);
// Initiate first class.
const firstClass = new FirstClass();
// Call firstClass method getResult.
const result = firstClass.getResult();
// Check whether the result is correct.
expect(result).to.deep.equal(fakeResult);
// Verify stub get called.
expect(stubDependencyGetResult.calledOnce).to.equal(true);
// Restore stub.
stubDependencyGetResult.restore();
});
});
});
When I run it using mocha:
$ mocha stackoverflow.spec.js
FirstClass.js
getResult()
✓ throws an exception if the result is not returned
1 passing (6ms)
$
Hope this helps.
In putting together getters and setters I realized that they aren't required.
What am I missing? How to ensure that when i call attributes they are the ones on the class ?
'use strict';
const { Book } = require('../app');
const { Page } = require('../page');
const { Bookmark } = require('../bookmark');
//
const chai = require('chai');
const expect = chai.expect;
it('has a bookmark', function () {
let bookmark = new Bookmark('bookmark');
bookmark.material = 'paper';
bookmark.mm='a';
expect(bookmark.mm).to.equal('a');
expect(bookmark.material).to.equal('paper');
})
#../bookmark.js
class Bookmark {
constructor(name) {
this.name = name;
}
}
exports.Bookmark = Bookmark;
What would be the unit test which would fake the calls to callActivity in the orchestrator below to return a known value and to expect that the orchestrator returns that value.
The examples on the azure durable functions documentation for unit testing[1] are all written in C# and I've not been able to replicate
them in javascript despite several attempts. This is because I don't know how to construct an orchestrator with a fake context.
const df = require('durable-functions');
module.exports = df.orchestrator(function* orchestratorFunctionGenerator(context) {
const input = context.df.getInput();
const apimApiName = input.apimApiName;
const indexNames = yield context.df.callActivity('GetIndexNames', apimApiName);
const indexerName = indexNames.idle;
const indexerStatus = yield context.df.callActivity('GetIndexerStatus', indexerName);
return indexerStatus;
});
[1] https://learn.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-unit-testing
The approach we went with was to extract the generator method out into it's own module.
module.exports = function* orchestratorFunctionGenerator(context) {
const input = context.df.getInput();
const apimApiName = input.apimApiName;
const indexNames = yield context.df.callActivity('GetIndexNames', apimApiName);
const indexerName = indexNames.idle;
const indexerStatus = yield context.df.callActivity('GetIndexerStatus', indexerName);
return indexerStatus;
};
then require it
const df = require('durable-functions');
const generatorFunction = require('./generator-function');
module.exports = df.orchestrator(generatorFunction);
and then test the function in isolation
const chai = require('chai');
const sinon = require('sinon');
const getIndexerStatusOrchestratorGenerator = require('../../GetIndexerStatusOrchestrator/generator-function');
const expect = chai.expect;
function iterateGenerator(generator) {
let result = generator.next();
while (!result.done) {
result = generator.next(result.value);
}
return result;
}
describe('getIndexerStatusOrchestrator', () => {
it('happy path should return \'inProgress\'', () => {
const indexNames = { active: 'index-1', idle: 'index-2' };
const apimApiName = 'api';
const input = { apimApiName };
const stubCallActivity = sinon.stub();
stubCallActivity.withArgs('GetIndexNames', apimApiName).returns(indexNames);
stubCallActivity.withArgs('GetIndexerStatus', indexNames.idle).returns('inProgress');
const context = {
df: {
callActivity: stubCallActivity,
getInput: sinon.fake.returns(input),
},
};
const generator = getIndexerStatusOrchestratorGenerator(context);
const result = iterateGenerator(generator);
expect(result.value).to.equal('inProgress');
});
it('indexer status should be for the idle index', () => {
const indexNames = { active: 'index-1', idle: 'index-2' };
const apimIndexName = 'api';
const input = { apimApiName: apimIndexName };
const stubCallActivity = sinon.stub();
stubCallActivity.withArgs('GetIndexNames', apimIndexName).returns(indexNames);
stubCallActivity.withArgs('GetIndexerStatus', indexNames.idle);
// use stub as a mock since we need both stub and mock behaviour
// for 'callActivity' and this was the easier option
stubCallActivity.withArgs('GetIndexerStatus').callsFake((method, indexerName) => {
expect.fail(`Unexpected indexer name ${indexerName}`);
});
const context = {
df: {
callActivity: stubCallActivity,
getInput: sinon.fake.returns(input),
},
};
const generator = getIndexerStatusOrchestratorGenerator(context);
iterateGenerator(generator);
// expectations set above
});
});
As might be expected this a trivial example of an orchestrator. We have orchestrators which have considerably more logic in them and where the tests will have more value.
In addition, I personally would not use the mocking approach in the 2nd test and would just rely on testing the outputs using stubs to fake dependency interactions.
I am trying to understand JavaScript inheritance and I hit a road block. I am not familiar with JavaScript's prototype based inheritance. I am still using old NodeJS version so I can't use classes.
Could you tell me why following code prints the same values for different workers and how can I prevent it?
var Manager = require('./manager');
var worker1 = new Manager.getWorker('foo');
var worker2 = new Manager.getWorker('bar');
console.log(worker1.config);
console.log(worker2.config);
//Implementation Details
//Manager
(function() {
'use strict';
function Manager() {
}
Manager.getWorker = function(slug) {
var Worker = null;
try {
Worker = require('./workers/' + slug);
Worker = new Worker();
} catch (e) {
console.log('Worker error: cannot initiate worker');
}
return Worker;
};
module.exports = Manager;
})();
//foo.js
(function () {
var _abstract = require('../abstract_worker');
var _util = require('util');
var config = {
"slug": "foo",
"name": "Foo Worker"
};
function Foo() {
this.config = config;
Foo.super_.apply(this,arguments);
}
_util.inherits(Foo, _abstract);
module.exports = Foo;
})();
//bar.js
'use strict';
(function () {
var _abstract = require('../abstract_worker');
var _util = require('util');
var config = {
"slug": "bar",
"name": "Bar Worker"
};
function Bar() {
this.config = config;
Bar.super_.apply(this,arguments);
}
_util.inherits(Bar, _abstract);
module.exports = Bar;
})();
(function() {
'use strict';
//config
var _ = require('lodash');
var default_config = {
number_of_job: 1
};
function AbstractWorker() {
if (!this.config) {
this.config = {};
}
if (!_.isString(this.config.slug)) {
throw new Error('config.slug is undefined.');
}
if (!_.isString(this.config.name)) {
throw new Error('config.name is undefined.');
}
this.config = _.merge(default_config, this.config);
}
module.exports = AbstractWorker;
})();
EDIT: Thanks to #Bergi I found out the source of the error. It seems Lodash's merge recursively merges own and inherited enumerable string keyed properties of source objects into the destination object. In my code it seems I also made a typo and wrote in wrong order. I just leave it as it is maybe it can help others in the long run.
this.config = _.merge(default_config, this.config);
is your problem. It assigns the same default_config object to all workers.