I am working on writing some some tests for a function I wrote: the current code works as I would expect it but now I need to DRY my code and refactor.
Below you will see the unit tests I've writtern:
QUnit.test('Localized Date in Honolulu', assert => {
const stub = sinon.stub(constantDate, 'getTimezoneOffset', () => {
return '600';
});
console.log('timeSet', timeSet());
assert.strictEqual(timeSet(), '2017-07-29T14:00:00.000Z', 'there needs to be a message here');
stub.restore();
});
QUnit.test('San Francisco Date and Time', assert => {
const stub = sinon.stub(constantDate, 'getTimezoneOffset', () => {
return '420';
});
assert.strictEqual(timeSet(), '2017-07-29T17:00:00.000Z');
stub.restore();
});
QUnit.test('Sydney time', assert => {
const stub = sinon.stub(constantDate, 'getTimezoneOffset', () => {
return '-600';
});
assert.strictEqual(timeSet(), '2017-07-30T10:00:00.000Z', 'Expected the time in Sydney to be 10AM');
stub.restore();
});
Although it seems to me that I should be able to refactor the stub I'm finding challenging because every stub has a different return value every time. Can I please get some suggestions as to how I can make my code clean and DRY.
One suggestion would be to use partial functions. As you're aware, the first two parameters in sinon.stub are the same for every unit test. So, before the unit tests execute we can create a function
const timezoneOffsetStub = (callback) => {
return sinon.stub(constantDate, 'getTimezoneOffset', callback);
}
(This assumes constantDate is a variable defined globally)
So now to stub in each unit test, we only have to define what the different callbacks are.
QUnit.test('Localized Date in Honolulu', assert => {
const stub = timezoneOffsetStub(() => '600');
...
});
QUnit.test('San Francisco Date and Time', assert => {
const stub = timezoneOffsetStub(() => '420');
...
});
Related
I am trying to mock a date object that will be utilized for all the unit test cases. I have many references for javascript, but that is not working in typescript due to type errors. can anyone provide a solution to overcome this issue?
// sampleMethod() Test Suite
describe('sample Method', () => {
it('should match two objects', () => {
// Preparing
const sampleRequest: sampleRequestType = {
key: '0',
status: 'success',
creation_time: new Date(),
attempts: 0,
last_attempt_time: new Date()
};
// Executing
const result = sampleobject.sampleMethod();
// Verifying
expect(result).toEqual(sampleRequest); // assume result also return the same value as sampleRequest
});
});
As Jest is developed on top of jasmine, you can use this
const mockDate = new Date(1434319925275);
spyOn(window, 'Date').and.callFake(() => {
return mockDate;
});
#hari you can refactor your sampleMethod and remove the hard dependency on the Date object.
Instead of instantiating directly the Date object (new Date) inside of the method , change the method and receive the date object as parameter.
In that way , you can easily mock the Date dependency.
I'm learning how to write tests for my code and my instructor explained to put the component being rendered in a beforeEach() function like this...
describe('CommentBox', () => {
let component;
beforeEach(() => {
component = renderComponent(CommentBox);
});
it('has the correct class', () => {
expect(component).to.have.class('comment-box');
});
it('has a text area', () => {
expect(component.find('textarea')).to.exist;
});
it('has a button', () => {
expect(component.find('button')).to.exist;
});
});
Why use beforeEach(). Why not just declare the component variable at the top of the describe function like so...
describe('CommentBox', () => {
const component = renderComponent(CommentBox);
it('has the correct class', () => {
expect(component).to.have.class('comment-box');
});
it('has a text area', () => {
expect(component.find('textarea')).to.exist;
});
it('has a button', () => {
expect(component.find('button')).to.exist;
});
});
This would seem to save a couple extra lines of code, and one less function you would have to write?
The beforeEach runs before each test. This means that each test gets fresh data to test with.
If you do it the other way each test could modify the object and then taint the object for the next test.
Its good practice to not create dependencies between tests so that you can more accurately find bugs or ensure your test actually tests the logic you intended.
I assume that your testing renderComponent.
I'm learning TDD from this article and the author talks about how Mocha's beforeEach will run a code before each assertion for you. But I don't understand why you need to do that when you can just run the code in the describe scope.
describe('Test suite for UserComponent', () => {
beforeEach(() => {
// Prevent duplication
wrapper = shallow(<UserComponent
name={ 'Reign' }
age={ 26 } />);
});
it('UserComponent should exist', () => {
expect(wrapper).to.exist;
});
it('Correctly displays the user name and age in paragraphs wrapped under a parent div', () => {
expect(wrapper.type()).to.equal('div');
// more code...
});
});
But not using the beforeEach would still work -
describe('Test suite for UserComponent', () => {
wrapper = shallow(<UserComponent
name={ 'Reign' }
age={ 26 } />);
it('UserComponent should exist', () => {
expect(wrapper).to.exist;
});
it('Correctly displays the user name and age in paragraphs wrapped under a parent div', () => {
expect(wrapper.type()).to.equal('div');
// more code...
});
});
beforeEach is executed before each test. This iteration is lost when the code is moved from beforeEach to be directly inside the function passed to describe. However, that's not all.
In some cases, code executed directly inside the function passed to describe can perform the same task as a beforeEach hook. For instance, if its function is to initialize a read-only structure that is local to the test in the describe block, then you could skip the beforeEach hook.
However, Mocha executes right away all the callbacks that are passed to describe calls whereas a beforeEach call registers the function passed to it for future execution, and it will be executed only if needed. If the initialization is expensive it is better to use a beforeEach hook because if you make use of --grep to select only some test, or use it.only to run a single test, then Mocha will run the hook only if it pertains to the test it will actually run. If you have the initialization code in describe, Mocha cannot skip it so you'll pay the initialization cost every time. However, if you are going to use a hook and the data is immutable, then before is better than beforeEach because it will run just once instead of before each test.
Then there are cases where running code in directly in the function passed to describe simply won't work. Imagine in the following that sharedResource is a resource that all tests need to use. It could be a third-party library that carries state, for instance. Some tests need it to be set to a certain state. Other tests need it to be in a different state. This does not work:
"use strict";
const assert = require('assert');
let sharedResource;
describe("in condition a", () => {
sharedResource = true;
it("sharedResource is true", () => assert(sharedResource));
});
describe("in condition b", () => {
sharedResource = false;
it("sharedResource is false", () => assert(!sharedResource));
});
The first test will fail because the execution order of the key statements is:
sharedResource = true;
sharedResource = false;
assert(sharedResource);
assert(!sharedResource);
The problem can be easily fixed by using beforeEach. This runs fine:
"use strict";
const assert = require('assert');
let sharedResource;
describe("in condition a", () => {
beforeEach(() => {
sharedResource = true;
});
it("sharedResource is true", () => assert(sharedResource));
});
describe("in condition b", () => {
beforeEach(() => {
sharedResource = false;
});
it("sharedResource is false", () => assert(!sharedResource));
});
I tried to test this code:
redireccion() {
this.$state.go('modifyLine', {lineId: this.look()._id});
}
look() {
return Entries.findOne({name: this.entry.name});
}
the code above method is ok (look), but for 'redireccion' I tried something like this and i got an error.
this is the code:
describe('redireccion()', () => {
beforeEach( inject(($state) => {
spyOn($state, 'go');
spyOn(controller, 'look');
spyOn(Entries, 'findOne');
}));
it('should be a ... bla bla', () => {
controller.redireccion();
expect($state.go).toHaveBeenCalledWith('modifyLine', {lineId: });
});
});
This is an excerpt, because really I do not know how testing this.
I will try to give you an insight. You should try to make your tests isolated... That means that if you're testing your redirection, you can mock the look method since it's not relevant (for this specific test).
describe('testing redirection()', () => {
beforeEach( inject(($state) => {
//here I'm saying that I'm spying every call to $state.go
spyOn($state, 'go');
//And here I'm that I'm not only spying every call to
//controller.look() but I'm also replacing the original
//implementation with my fake one. Every call will basically
//return an object with id equals 10
spyOn(controller, 'look').and.callFake(() => {
var mockedLine = {
_id: 10
};
return mockedLine;
});
}));
it('should call state.go', () => {
controller.redireccion();
//if you just want to check if the method was called, do the following:
expect($state.go).toHaveBeenCalled();
//if you need to also check the arguments, try:
var args = $state.go.mostRecentCall.args;
expect(args[0]).toBe('modifyLine');
expect(args[1].lineId).toBe(10);
});
});
I have the following spec.
describe("SN.ExitHistory", function() {
var exitHistory;
beforeEach(function() {
SN.Utils = jasmine.createSpy("utils").andCallFake(function() {
function readSNCookie(cookieName, key) {
return "google.com";
}
function isUndefinedOrNull(param) {
return (param == null) || (param === "null");
}
function createSNCookie(snCookieName, key, value, lifeTime) {
}
var me = {
readSNCookie : readSNCookie,
isUndefinedOrNull : isUndefinedOrNull,
createSNCookie : createSNCookie
};
return me;
})();
exitHistory = SN.ExitHistory();
});
it("return last exit link", function() {
expect(exitHistory.getLastExitLink()).toEqual("google.com");
});
});
exitHistory.getLastExitLink internally use SN.Utils.
After the test is done Jasmine does not remove the spy object utils. In next test suite also I can see the same utils present. Is there any way to reset the spy object after each test is done?
Instead of creating spy, if I create a new object for utils, behavior is same. Then what is the difference between a spy and actual object in this scenario.
Correct me if I am wrong.
I had the same problem some time ago and after days of struggling I found the solution. If you use the other way your spy will be reseted, so try with
spyOn(SN, 'Utils');
Spies are described here:
https://github.com/pivotal/jasmine/wiki/Spies
Use spyOn and declare your spies within a before block inside of a describe spec block and the spies will be cleaned up when each spec is torn down.
aSpec.js
describe('something', () => {
beforeAll(() => spyOn(someObject, 'someMethod').and.returnValue('foo'));
it('is spied on', () => {
expect(someObject.someMethod()).toEqual('foo');
});
});
anotherSpec.js
describe('something else', () => {
beforeAll(() => spyOn(someObject, 'someMethod').and.returnValue('bar'));
it('is spied on', () => {
expect(someObject.someMethod()).toEqual('bar');
});
});