I m actually using a micro framework created by my society in which we use Mongoose.
To manage the mongoose object, we created a modelfactory, that returns us a model corresponding to the mongoose name object.
Actually, I m working on an authentication service in which I inject this modelfactory.
I need to unit test it with mocha and sinonjs, but I m a bit lost...
This is my authentication Service method that I want to test :
class AuthenticationService extends Service
constructor: (modelFactory)->
super(modelFactory)
#authorizedClientIds = [
"123456"
"toto"
]
#OAuthAccessTokensModel = #modelFactory.getSchema('OAuthAccessTokens')
#OAuthClientsModel = #modelFactory.getSchema('OAuthClients')
#OAuthUsersModel = #modelFactory.getSchema('OAuthUsers')
#OAuthRefreshTokensModel = #modelFactory.getSchema('OAuthRefreshTokens')
## Get an access token from the bearer token ##
getAccessToken: (bearerToken, callback)->
#OAuthAccessTokensModel.findOne({accessToken: bearerToken}, callback)
module.exports = AuthenticationService
I want to test the getAccessToken method, but I have clearly no idea how to make it work...
I've tried to make something like :
describe("Authentication Service", function () {
var service;
before(function () {
ModelFactory = use('/app/core/config/database/ModelFactory');
var mock = sinon.mock(ModelFactory.getFactoryInstance([]));
mock.expects("getSchema").withArgs("user").return({name:'user',getName:function(){}});
service = new AuthenticationService(mock);
});
describe("getAccessToken", function () {
it('should return-1 when the value is not present', function () {
var proxy = once(service.getAccessToken());
mock.verify();
});
});
});
How should I do to test it correctly ?
EDIT :
I've tried something, but it seems weird to test because I propose the result to compare, but the result expected too.. So I could never fail the test :x...
describe("Authentication Service", function () {
var service;
before(function () {
ModelFactory = use('/app/core/config/database/ModelFactory');
var factory = new ModelFactory([]);
sinon.stub(factory, "getSchema").returns({findOne: sinon.stub().returns()});
service = new AuthenticationService(factory);
});
describe("getAccessToken", function () {
it('Check if the access token correspond to a database entry', function () {
stubResult = {token: '123456'};
service.getAccessToken = sinon.stub().withArgs('1234').returns(undefined);
assert.equal(service.getAccessToken(), undefined);
});
});
});
Some help ?
Thanks for advance
The Unit test should test something that is not mocked/stubbed.
When you have a difficult method handleUnknownToken() this function can call your Authentication Service. The assert() should verify that the handling of the 'undefined' works as expected.
In other words: When you want to unit test f(x) = g()+h() +j(); you can test the correct implementation of g() by stubbing h() and j(), test h() by stubbing g() and j() and test j() by stubbing g() and h().
EDIT: The explanation above is abstract, since I do not know Mongoose/Mocha/Sinonjs. Beneath I'll try to focus on the case described.
When your service getAccessToken() is completely stubbed, the next tests
will succeed when your stub definition is correct:
testUnknown() {
constant UKNOWN_ITEM='1234';
assert.equal(service.getAccessToken(UNKNOWN_ITEM), undefined);
}
testTimeout() {
constant DIFFICULT_ITEM='1235';
assert.equal(service.getAccessToken(DIFFICULT_ITEM), STATUS_TIMEOUT);
}
testRevoked() {
constant REVOKED_ITEM='1236';
assert.equal(service.getAccessToken(REVOKED_ITEM), STATUS_DENIED);
}
testActive() {
constant ACTIVE_ITEM='1237';
assert.equal(service.getAccessToken(ACTIVE_ITEM), STATUS_OK);
}
Your test must include some logic you don't stub.
Waht is the code around calling getAccessToken()? Something like a function
isTokenOK(), that will look at the status and retry 5 times after a timeout?
With the stubs implemented for the above test you can test the boolean function isTokenOK() with
testUnknown() {
assertFalse(isTokenOK(UNKNOWN_ITEM));
}
testTimeout() {
assertFalse(isTokenOK(DIFFICULT_ITEM));
}
testRevoked() {
assertFalse(isTokenOK(REVOKED_ITEM));
}
testActive() {
assertTrue(isTokenOK(ACTIVE_ITEM));
}
And now, when somebody changes the implementation of isTokenOK(), your unit test can fail. When the unit test is failing, you must look who is right.
Maybe a token that has been revoked can be used for authentication the first 10 minutes after revocation and isTokenOK(REVOKED_ITEM) should be true.
Oh well, than you must add a new test for REVOKED_ITEM_YESTERDAY.
Related
I'm trying to stub a function using sinon. The function has the following signature
export function getIndexDocument(
svc: MetaHTTPService | ServiceConfig
): MetaPromise<RepoResponseResult<IndexDocument>> {
Is this the right way to sub it
sandbox.stub(getIndexDocument).resolves({} as RepoResponseResult)
I tried that but it returns an error.
Here's how this function is called.
I have a class called AssetsController with the following functions
public async exploreIndexDocument(): Promise<Asset | undefined> {
// it makes an HTTP request and returns a promise that resolves with the following info { repoId: "", assetId: "" }
const {
result: { assignedDirectories }
} = await getIndexDocument(this.serviceConfig).catch(err => {
throw new Error(`Bad repsonse`);
});
return {
repoId: result.repoId;
assetId: result.assetId
}
}
public async function copyAsset(asset) {
const res = await this.exploreIndexDocument();
const repoId = res.repoId;
return asset.copy(repoId);
}
I'm trying to test the function copyAsset, but it calls exploreIndexDocument which calls getIndexDocument. getIndexDocument is imported at the top of the file and lives in the module #ma/http.
getIndexDocument makes an HTTP request.
How can I test copyAsset given that it calls getIndexDocument which makes an HTTP request?
According to the docs, you can't stub an existing function.
You can:
// Create an anonymous sstub function
var stub = sinon.stub();
// Replaces object.method with a stub function. An exception is thrown
// if the property is not already a function.
var stub = sinon.stub(object, "method");
// Stubs all the object’s methods.
var stub = sinon.stub(obj);
What you can't do is stub just a function like:
var stub = sinon.stub(myFunctionHere);
This makes sense because if all you have is a reference to a function, then you can just create a new function to use instead, and then pass that into where ever your test needs it to go.
I think you just want:
const myStub = sandbox.stub().resolves({} as RepoResponseResult)
In your update it sounds like you want to put the stub on the AssetsController class. See this answer for more info on that, but in this case I think you want:
const myStub = sandbox
.stub(AssetsController.prototype, 'exploreIndexDocument')
.resolves({} as RepoResponseResult)
Now anytime an instance of AssetsController calls its exploreIndexDocument method, the stub should be used instead.
Playground
I think most of your problems can be solved by revisiting your architecture. For example, instead of creating an explicit dependency on getIndexDocument within your AssetController class you can simply inject it in. This will allow you to swap implementations depending on the context.
type IndexDocumentProvider = (svc: MetaHTTPService | ServiceConfig) => MetaPromise<RepoResponseResult<IndexDocument>>;
interface AssetControllerOptions {
indexDocumentProvider: IndexDocumentProvider
}
class AssetController {
private _getIndexDocument: IndexDocumentProvider;
public constructor(options: AssetControllerOptions) {
this._getIndexDocument = options.indexDocumentProvider;
}
}
Then you can use this._getIndexDocument wherever and not worry about how to make the original implementation behave like you want in your tests. You can simply provide an implementation that does whatever you'd like.
describe('copyAsset', () => {
it('fails on index document error.', () => {
const controller = new AssetController({
indexDocumentProvider: () => Promise.reject(new Error(':('));
});
....
});
it('copies asset using repo id.', () => {
const controller = new AssetController({
indexDocumentProvider: () => Promise.resolve({ repoId: "420" })
});
...
});
});
You can obviously use stubs instead of just functions or whatever if you need something fancy.
Above we removed an explicit dependency to an implementation and instead replaced it with a contract that must be provided to the controller. The is typically called Inversion of Control and Dependency Injection
I have a setup similar to this question but the partial mocking answer is not working for me.
I have a file 'FiscalYear.jsx' which contains a class FiscalYear and a few related non-class functions eg
export class FiscalYear {
constructor(fy) { //does stuff }
// other functionality
}
export function getFY(offset) {
// does stuff
return new FiscalYear(fy);
}
I want my Jest test for the getFY function to simply check that the FiscalYear constructor was called with the right parameter. I used partial mocking in my test file to accomplish this:
import { FiscalYear, getFY } from '../FiscalYear';
jest.mock('../FiscalYear', () => {
const originalModule = require.requireActual('../FiscalYear');
return {
...originalModule,
FiscalYear: jest.fn().mockImplementation((a) => { })
};
});
test("getFY", () => {
getFY(2);
expect(FiscalYear).toHaveBeenCalled();
});
I'll update the toHaveBeenCalled to toBeCalledWith once I make it actually call the function. However currently the test fails with
expect(jest.fn()).toHaveBeenCalled()
Expected number of calls: >= 1
Received number of calls: 0
I put a console.log in the real constructor and confirmed that the getFY function is calling that instead of the mock constructor.
How to get this working? Is it a bad design to have these both in the same file? Totally new to JavaScript so if this is bad practice please let me know.
I'm testing code that instantiates an object from an external library. In order to make this testable, I've decided to inject the dependency:
Boiled down to:
const decorator = function (obj, _extLib) {
var ExtLib = _extLib || require('extlib')
config = determineConfig(obj) //This is the part that needs testing.
var el = new ExtLib(obj.name, config)
return {
status: el.pay({ amt: "one million", to: "minime" })
bar: obj.bar
}
}
In my test, I need to determine that the external library is instantiated with the proper config. I'm not interested in whether this external library works (it does) nor wether calling it, gives results. For the sake of the example, let's assume that on instantiating, it calls a slow bank API and then locks up millions of dollars: we want it stubbed, mocked and spied upon.
In my test:
it('instantiates extLib with proper bank_acct', (done) => {
class FakeExtLib {
constructor(config) {
this.acct = config.bank_acct
}
this.payMillions = function() { return }
}
var spy = sandbox.spy(FakeExtLib)
decorator({}, spy) // or, maybe decorator({}, FakeExtLib)?
sinon.assert.calledWithNew(spy, { bank_acct: "1337" })
done()
})
Do note that testing wether e.g. el.pay() was called, works fine, using spies, in sinon. It is the instantiation with new, that seems untestable.
To investigate, let's make it simpler even, testing everything inline, avoiding the subject under test, the decorator function entirely:
it('instantiates inline ExtLib with proper bank_acct', (done) => {
class ExtLib {
constructor(config) {
this.acct = config.bank_acct
}
}
var spy = sandbox.spy(ExtLib)
el = new ExtLib({ bank_acct: "1337" })
expect(el.acct).to.equal("1337")
sinon.assert.calledWithNew(spy, { bank_acct: "1337" })
done()
})
The expect part passes. So apparently it is all called properly. But the sinon.assert fails. Still. Why?
How can I check that a class constructor is called with proper attributes in Sinon?" Is calledWithNew to be used this way? Should I spy on another function such as the ExtLib.prototype.constructor instead? If so, how?
You're really close.
In the case of your simplest example, you just need to create el using the spy instead of ExtLib:
it('instantiates inline ExtLib with proper bank_acct', (done) => {
class ExtLib {
constructor(config) {
this.acct = config.bank_acct
}
}
var spy = sandbox.spy(ExtLib)
var el = new spy({ bank_acct: "1337" }) // use the spy as the constructor
expect(el.acct).to.equal("1337") // SUCCESS
sinon.assert.calledWithNew(spy) // SUCCESS
sinon.assert.calledWithExactly(spy, { bank_acct: "1337" }) // SUCCESS
done()
})
(Note that I modified the test to use calledWithExactly to check the arguments since calledWithNew doesn't seem to check the arguments properly in v7.2.2)
I can get tests to run in Intern, but I am struggling with getting spies to work. I'm trying to integrate sinon so I can get spies. Here is a sample test file:
define([
'intern!bdd',
//'intern/chai!expect',
//'intern/order!node_modules/intern/chai',
// 'intern/order!node_modules/chai/lib/chai',
// 'intern/order!node_modules/sinon/lib/sinon',
// 'intern/order!node_modules/sinon-chai/lib/sinon-chai',
'intern/order!node_modules/sinon/lib/sinon',
'intern/order!node_modules/sinon/lib/sinon/spy',
'intern/order!node_modules/sinon/lib/sinon/call',
'intern/order!node_modules/sinon/lib/sinon/behavior',
'intern/order!node_modules/sinon/lib/sinon/stub',
'intern/order!node_modules/sinon/lib/sinon/mock',
'intern/order!node_modules/sinon/lib/sinon/collection',
'intern/order!node_modules/sinon/lib/sinon/assert',
'intern/order!node_modules/sinon/lib/sinon/sandbox',
'intern/order!node_modules/sinon/lib/sinon/test',
'intern/order!node_modules/sinon/lib/sinon/test_case',
'intern/order!node_modules/sinon/lib/sinon/match',
'intern/order!vendor/src/angular/angular',
'intern/order!vendor/src/angular-mocks/angular-mocks',
'intern/order!src/common/modules/error_handling/error_handling'
], function (bdd, sinon, spy, call, behavior, stub, mock, collection, assert, sandbox, test, test_case, match) {
with (bdd) {
sinon.spy = spy;
sinon.call = call;
sinon.behavior = behavior;
sinon.stub = stub;
sinon.mock = mock;
sinon.collection = collection;
sinon.assert = assert;
sinon.sandbox = sandbox;
sinon.test = test;
sinon.test_case = test_case;
sinon.match = match;
describe('Error handler module', function () {
var test, scope, ctrl, error_handler, log;
function inject (fn) {
return function() {
angular.injector(['ng', 'ngMock', 'error_handling']).invoke(fn);
}
}
beforeEach(inject(function($log){
log = $log;
}));
it('should be an object', function(){
//expect(log).to.be.an('object');
});
it('should call console.trace with the string test', function(){
var spy = sinon.spy(console.trace);
//expect(sinon.spy).to.be.ok;
//log.debug('test');
console.trace('test');
//spy.should.be.ok;
spy.should.have.been.calledWith('test');
//chai.expect(spy).to.have.been.called.with('test');
});
});
}
});
I based it off of https://github.com/theintern/intern/blob/sinon/sinon.js
But I get this error failure:
>> 1/6 tests failed
Warning: FAIL: main - Error handler module - should log nothing when the logging mode is off (1ms)
TypeError: 'undefined' is not an object (evaluating 'spy.should.have')
at </Users/evanvandegriff/Documents/work/nomi_v2/nomi_v2/web/src/common/modules/error_handling/error_handling.test.js:67>
at <__intern/lib/Test.js:169>
at <__intern/lib/Suite.js:237>
at <__intern/node_modules/dojo/Deferred.js:37>
at <__intern/node_modules/dojo/Deferred.js:258>
at runTest <__intern/lib/Suite.js:241>
at <__intern/lib/Suite.js:249
Anyone have any ideas why this isn't working?
As #Fordio indicated, the syntax you're trying to use is part of Sinon-Chai, not vanilla Sinon.js. You'll need to require that package as a dependency, or use the native Sinon.js assertions.
I'm starting to write some javascript tests and trying to figure out what the best approach is for inspecting the private members of a module constructor. For example, in the sample below i'm using the revealing module pattern to expose the public api to my module. I want to test that privateVar is correctly set during the callback of the $.getJSON ajax request.
The second test it('should update privateVar', ...), doesn't work because myModule.privateVar is (intentionally) not in the public api for the module.
So, my question is, What is the best way to test this kind of behaviour without having to make the privateVar part of the public api? Is there a better way to factor this code for testing, or maybe a way to use something like SinonJs to spy on the private member?
define('myModule',
['jquery'],
function ($) {
var
myVar = "something",
privateVar = "something else",
doSomething = function() {
return $.getJSON('http://myapi.com/do-something', { requestData : "some data" }, function(response){
myVar = response.data.value1;
privateVar = response.data.value2;
});
};
return {
doSomething : doSomething,
myVar : myVar
};
}
);
define('test/test.myModule',
['myModule', 'chai', 'sinon', 'mocha'],
function (myModule, chai, sinon) {
describe("myModule", function() {
var expect = chai.expect;
describe('doSomething', function() {
var value1 = 'value1 value',
value2 = 'value2 value';
beforeEach(function() {
sinon.stub($, 'ajax').yieldsTo('success', {
data : { value1 : value1, value2 : value2 }
});
});
afterEach(function() {
$.ajax.restore();
});
it('should update myVar', function(done) {
myModule.doSomething();
expect(myModule.myVar).to.equal(value1);
done();
});
it('should update privateVar', function(done) {
myModule.doSomething();
expect(myModule.privateVar).to.equal(value2);
done();
});
});
});
}
);
What you are talking about here unfortunately requires an integration test, you wish to test that a variable is set as a result of an external operation, You should trust that the external method just works for your test by stubbing it out in your tests as you have done with sinon this takes care of the external call.
What you need to be able to do is to control the conditions of the test (lets say non authenticated and authenticated) then test what the result of the function is in that instance. As a rule I don't normally test private members at all but I do test desired behaviour resulting from known good and bad values..
I also read this a little while ago, which discusses private vars.
The only way you can access your private variables this way is is to add a public getter that you can later call in your test to verify the state:
In your class:
getPrivateVar : function(){ return privateVar; }
Then add to return statement:
return { getPrivateVar : getPrivateVar, };
Actually why test a private variable? It is not possible/difficult.
And what is the purpose of that variable? If it is going to be passed on as a argument to function, you can of-course test the function by spying if the function is called with the specific value, which was assigned to the private variable.
You can use rewire
let revertBack = renderCtrl.__set__(privateMember,substituteMember);
to revert back just call revertBack();
For more details see https://www.npmjs.com/package/rewire