When (and how) should I remove a proxyquire/sinon mock - javascript

**edit: I restored the mocked function after test1, using sinon.restore(), but again, it feels unnecessary to restore all mocks when I just want to restore one.
Just wondering when and how I should remove this mocked module?
It's only needed for test1, and needs to be removed (or at least changed) for test2.
afterEach might work I guess, but it doesn't need to be reset after every test, just one. ~
I could move test1 into its own describe block, but this seems a bit unnecessary
I could just remove the mock in the describe block itself, but I'm not sure if that would work as expected
I could just change the mockedFn, but again, I'm not sure where best to do it
The docs also say that I should call proxyquire.del('../../utils/validation') to remove the overrides, but this results in an error: TypeError: proxyquire.del is not a function, which seems a bit odd?
const proxyquire = require('proxyquire');
let validationModule;
describe('Unit Test Examples', () => {
// Module/function mocked before test1
const mockedFn = sinon.stub();
mockedFn.returns(null);
validationModule = proxyquire('../../utils/validation', {
'../models/Person': {
findOne: mockedFn
}
});
it('test1', () => {});
// Removed after test1?
it('test2', () => {});
})

Related

How to test an internal function

I'm trying to create a unit test to cover an internal function
fileA.js
module.exports.functionA = () {
const functionB = () {
// do something
}
functionB()
}
test.js
const { functionA } = require('fileA')
...
it('runs functionB', () => {
functionA()
expect(...).toHaveBeenCalled()
}
How do I access it?
There are two possibilities here (your situation looks like the first one, but is also clearly simplified for the purposes of the question).
Either:
functionB is entirely private to functionA, part of its implementation, which means you can't access it to test it (directly). Instead, test functionA, which presumably uses functionB as part of the work it does (otherwise, there's no point in an entirely private function in functionA).
or
functionA exposes functionB in some way (for instance, as a return value, or as a method on a returned object, or by setting it on an object that's passed in, etc.), in which case you can get it in whatever way functionA provides and then test it.
(Again, I think yours is the first case.)

Sinon stub only records react calls if it has been run before

Here is my code I'm testing:
const CardWarsComponent = props => {
const onSubmitCardMove = () => {
props.floopThePig()
}
return <Button id="FloopButtonId" onClick={onSubmitCardMove}>FLOOP IT</Button>
};
When I test I do this:
const floopStub = sinon.stub();
const wrapper = shallow(<CardWarsComponent floopThePig={floopStub}></CardWarsComponent>)
const button = wrapper.find('#FloopButtonId').dive();
const onClick = button.prop('onClick');
onClick();
wrapper.update();
expect(floopStub).to.have.been.calledOnce();
I find that I get this response:
TypeError: (0, _chai.expect)(...).to.have.been.calledOnce is not a function
BUT, if I call it once already:
const floopStub = sinon.stub();
floopStub()
const wrapper = shallow(<CardWarsComponent floopThePig={floopMock}></CardWarsComponent>)
Then I get:
expected floopThePig to have been called exactly once, but was called twice
floopThePig at Context.floopThePig
floopThePig at floopThePig
So why can I not get it called once, but after calling it once...I get the second (actual test) call?
The initial error message you got is exactly correct - looking at the Sinon docs, .calledOnce is a not a function, it's a javascript get that runs code. In general, Chai expectations only seem to be functions if they need parameters.
I find this a bit annoying because get overloading isn't very nice and breaks our ability to reason about the code, and it sets off a bunch of lint errors, but hey ho.
Changing your expect to
expect(floopStub).to.have.been.calledOnce;
fixes the test (at least on my machine!)
The reason the code seems to "work" in your second example is because the test resolves the calledOnce get operation, which checks the condition and throws a test failure assertion, so there's never a chance to throw the original error by trying to call the get result as if it were a function.
Incidentally, it's easier to trigger the click event with enzyme's built-in .simulate() call. This code works fine:
const floopStub = sinon.stub();
const wrapper = shallow(<CardWarsComponent floopThePig={floopMock}></CardWarsComponent>);
wrapper.find('#FloopButtonId').dive().simulate('click');
expect(floopStub).to.have.been.calledOnce;
More info on testing React events with sinon/enzyme can be found here: https://www.leighhalliday.com/testing-react-jest-enzyme-sinon

How to properly stub a function return value?

Premise: JS ES6, NodeJS
Testing Framework: TAP
Mocking Library: testdouble.js
I am attempting to mock the return value for the method of my class and keep receiving this error:
not ok Unsatisfied verification on test double. Wanted: - called with (true). But there were no invocations of the test double.
Here is my testing code:
// Imports for unit testing
const tap = require('tap');
const Subject = require('../src/iTunesClient.js');
const td = require('testdouble');
let reqJson;
// Ensure the iTunes class methods are called
tap.test('iTunesClient class methods function as intended', (t) => {
t.beforeEach((ready) => {
reqJson = td.replace('../src/reqJson.js');
ready();
});
t.afterEach((ready) => {
td.reset();
ready();
});
t.test('iTunesClient.getData', (assert) => {
const callback = td.function();
const subject = new Subject();
subject.setTerm('abc 123');
subject.setURL();
td.when(reqJson.get(td.callback)).thenCallback(true);
subject.getData(callback);
td.verify(callback(true));
assert.end();
});
t.end();
});
Specifically, this line is related to my issue:
td.verify(callback(true));
How can I fake the callback value of true for reqJson.get()? Right now, Subject.geData() is a method of the iTunesClient class which calls another file, reqJson.js, to use its exported get() method.
It's a little hard to tell from your example, but it looks like you're requiring iTunesClient before you call td.replace. In this case, the real reqJson module will be required and cached on line 3.
You need to call td.replace early enough to avoid this, e.g. in between requiring tap and iTunesClient.
I wanted to update this question, as I recently solved this issue. Essentially, I had two issues:
Account for both reqJson function parameters
Account for all callback return values
Per testdouble documentation for item 1:
When passed td.matchers.anything(), any invocation of that test double function will ignore that parameter when determining whether an invocation satisfies the stubbing.
Hence, I adjusted my line of code as follows:
Before: td.when(reqJson.get(td.callback)).thenCallback(true);
After: td.when(reqJson.get(td.matchers.anything(), td.callback)).thenCallback(null, null, null);

Stubbing Date.now() and Math.random()

I'm using Mocha with Sinon to unit test my node.js modules. I've successfully mocked other dependencies (other modules that I've written), but I've run into problems stubbing non-pure functions (like Math.random() and Date.now()). I've tried the following (simplified so that this question isn't so localized), but Math.random() was not stubbed because of an obvious scope problem. The instances of Math are independent between the test file and mymodule.js.
test.js
var sinon = require('sinon'),
mymodule = require('./mymodule.js'),
other = require('./other.js');
describe('MyModule', function() {
describe('funcThatDependsOnRandom', function() {
it('should call other.otherFunc with a random num when no num provided', function() {
sinon.mock(other).expects('otherFunc').withArgs(0.5).once();
sinon.stub(Math, 'random').returns(0.5);
funcThatDependsOnRandom(); // called with no args, so should call
// other.otherFunc with random num
other.verify(); // ensure expectation has been met
});
});
});
So in this contrived example, functThatDependsOnRandom() would look like:
mymodule.js
var other = require('./other.js');
function funcThatDependsOnRandom(num) {
if(typeof num === 'undefined') num = Math.random();
return other.otherFunc(num);
}
Is it possible to stub Math.random() in this scenario with Sinon?
yes, this is an old question but it is valid. Here is an answer that works, though I'd love to hear suggestions on how to make it better.
The way I've dealt with this in the browser is to create a proxy object. For example, you can't stub the window object in the browser so you can create a proxy object called windowProxy. When you want to get the location you create a method in windowProxy called location that returns or sets windowLocation. Then, when testing, you mock windowProxy.location.
You can do this same thing with Node.js, but it doesn't work quite as simply. The simple version is that one module can't mess with another module's private namespace.
The solution is to use the mockery module. After initializing mockery, if you call require() with a parameter that matches what you told mockery to mock, it will let you override the require statement and return your own properties.
UPDATE: I've created a fully functional code example. It is on Github at newz2000/dice-tdd and available via npm. /END UPDATE
The docs are pretty good, so I suggest reading them, but here's an example:
Create a file randomHelper.js with contents like this:
module.exports.random = function() {
return Math.random();
}
Then in your code that needs a random number, you:
var randomHelper = require('./randomHelper');
console.log('A random number: ' + randomHelper.random() );
Everything should work like normal. Your proxy object behaves in the same way as Math.random.
It is important to note that the require statement is accepting a single parameter, './randomHelper'. We'll need to note that.
Now in your test, (I'm using mocha and chai for example):
var sinon = require('sinon');
var mockery = require('mockery')
var yourModule; // note that we didn't require() your module, we just declare it here
describe('Testing my module', function() {
var randomStub; // just declaring this for now
before(function() {
mockery.enable({
warnOnReplace: false,
warnOnUnregistered: false
});
randomStub = sinon.stub().returns(0.99999);
mockery.registerMock('./randomHelper', randomStub)
// note that I used the same parameter that I sent in to requirein the module
// it is important that these match precisely
yourmodule = require('../yourmodule');
// note that we're requiring your module here, after mockery is setup
}
after(function() {
mockery.disable();
}
it('Should use a random number', function() {
callCount = randomStub.callCount;
yourmodule.whatever(); // this is the code that will use Math.random()
expect(randomStub.callCount).to.equal(callCount + 1);
}
}
And that is it. In this case, our stub will always return 0.0.99999; You can of course change it.
It is easy to stub Date.now() with sinon by using Fake timers :
Fake timers provide a clock object to pass time, which can also be used to control Date objects created through either new Date(); or Date.now(); (if supported by the browser).
// Arrange
const now = new Date();
const clock = sinon.useFakeTimers(now.getTime());
// Act
// Call you function ...
// Assert
// Make some assertions ...
// Teardown
clock.restore();
Are you sure that not mocking Math is the problem. It seems that this line make not much sense:
sinon.mock(other).expects('otherFunc').withArgs(0.5).once();
you mock others in one module but use it in another one. I dont think that you will get the mocked version in mymodule.js. On the other hand stubbing Math.random should work, as this is global for all modules.
Also take a look at this SO for mocking dependencies in nodeJS tests.

Javascript: Mocking Constructor using Sinon

I am pulling my hair out trying to figure out how to mock a constructor using sinon. I have a function that will create multiple widgets by calling a constructor that accepts a few arguments. I want to verify that the constructor is called the correct number of times with the correct parameters, but I don't want to actually construct the widgets. The following links seemingly explain a straightforward way of mocking the constructor, however it does not work for me:
Spying on a constructor using Jasmine
http://tinnedfruit.com/2011/03/25/testing-backbone-apps-with-jasmine-sinon-2.html
When I make the following call to stub the constructor:
sinon.stub(window, "MyWidget");
I get the following error:
Uncaught TypeError: Attempted to wrap undefined property MyWidget as function
When debugging in Chrome I see MyWidget shows up in the Local section of the Scope Variables, however there is not MyWidget property off of window.
Any help would be greatly appreciated.
I needed a solution for this because my code was calling the new operator. I wanted to mock the object that the new call created.
var MockExample = sinon.stub();
MockExample.prototype.test = sinon.stub().returns("42");
var example = new MockExample();
console.log("example: " + example.test()); // outputs 42
Then I used rewire to inject it into the code that I was testing
rewiredModule = rewire('/path/to/module.js');
rewiredModule.__set__("Example", example);
From the official site of sinonjs:
Replaces object.method with a stub function. The original function can be restored bycalling object.method.restore(); (or stub.restore();). An exception is thrown if the property is not >already a function, to help avoid typos when stubbing methods.
this simply states that the function for which you want to create the stub must be member of the object object.
To make things clear; you call
sinon.stub(window, "MyWidget");
The MyWidget function needs to be within the global scope (since you pass window as parameter). However, as you already said, this function is in a local scope (probably defined within an object literal or a namespace).
In javascript everyone can have access to the global scope, but not the other way around.
Check where you declare the MyWidget function and pass container object as first parameter to sinon.stub()
Using Sinon 4.4.2, I was able to mock an instance method like this:
const testObj = { /* any object */ }
sinon.stub(MyClass.prototype, "myMethod").resolves(testObj)
let myVar = await new MyClass(token).myMethod(arg1, arg2)
// myVar === testObj
A similar solution provided here:
Stubbing a class method with Sinon.js
I used Mockery to Mock a Constructor/Function without any problems.
var mockery = require('mockery');
var sinon = require('sinon');
mockery.enable({
useCleanCache: true,
warnOnReplace: false,
warnOnUnregistered: false
});
exports.Client = function() {/* Client constructor Mock */};
var ClientSpy = sinon.spy(exports, 'Client');
mockery.registerMock('Client', ClientSpy);
var Factory = require('Factory'); // this module requires the Client module
You should be able to apply a Sinon Spy just as the example above does.
Make sure to disable or reset Mockery after the test(s)!
Use sinon.createStubInstance(MyES6ClassName), then when MyES6ClassName is called with a new keyword, a stub of MyES6ClassName instance will returned.
I ran into this error by mistakenly typing sinon.stub.throws(expectedErr) rather than sinon.stub().throws(expectedErr). I've made similar mistakes before and not encountered this particular message before, so it threw me.
Mocking and stubbing the constructor with sinon
I give two solutions. The first addresses the question, how to mock the constructor with behaviour, the second shows how to stub it with a dummy. Google guided me multiple times to this question for the search how to stub it.
Mocking the constructor with behaviour
I don't know if this is the shortest path. At least it does, what was asked for.
First I use sinon's fake method to create a mocking constructor Mock with the behaviour I want. Then I have to add the methods one by one. For reasons I didn't investigate, it did not work, when setting the whole prototype of UnderTest to Mock.
require('chai').should();
const { fake} = require('sinon');
class UnderTest {
constructor() {
this.mocked = false;
}
isMocked() {
return this.mocked;
}
}
describe('UnderTest', () => {
let underTest;
let isMocked;
before(() => {
const Mock = fake(function () { this.mocked = true; });
Mock.prototype.isMocked = UnderTest.prototype.isMocked;
underTest = new Mock();
isMocked = underTest.isMocked();
});
it('should be mocked', () => {
isMocked.should.be.true;
});
});
Stubbing the constructor with a dummy
If you are leaded to this post, because you just want to stub the constructor to keep it from being executed.
Sinon's createStubInstance creates a stubbed constructor. It also stubs all methods. Hence, the method under test has to be restored before.
require('chai').should();
const { createStubInstance } = require('sinon');
class UnderTest {
constructor() {
throw new Error('must not be called');
}
testThis() {
this.stubThis();
return true;
}
stubThis() {
throw new Error('must not be called');
}
}
describe('UnderTest', () => {
describe('.testThis()', () => {
describe('when not stubbed', () => {
let underTest;
let result;
before(() => {
underTest = createStubInstance(UnderTest);
underTest.testThis.restore();
result = underTest.testThis();
});
it('should return true', () => {
result.should.be.true;
});
it('should call stubThis()', () => {
underTest.stubThis.calledOnce.should.be.true;
});
});
});
});
Just found this in the documentation.
If you want to create a stub object of MyConstructor, but don’t want the constructor to be invoked, use this utility function.
var stub = sinon.createStubInstance(MyConstructor)
I was able to get StubModule to work after a few tweaks, most notably passing in async:false as part of the config when requiring in the stubbed module.
Kudos to Mr. Davis for putting that together

Categories