I would like to ask if can be tested calling the right function dependent on the condition with sinon or mocha. For example I have class Knight and I want to know if a function (knightRun) is called, when parameter 'data' is true.
export class Knight {
createKnight(data,reducer) {
if (data) {
this.knightRun(reducer);
} else if (!data) {
this.knightFight(reducer);
}
}
private knightFight(reducer) {
// do something
}
private knightRun(reducer) {
// do something
}
}
You can use spies to check whether a particular function has been called. Sinon.js is a library which provides a way to spy on functions when writing unit tests for your JavaScript.
e.g.
describe('Knight class', () => {
it('should call knightRun when data is false', () => {
const knight = new Knight().createKnight(false, null)
sinon.spy(knight, "knightRun")
assert(knight.knightRun.calledOnce)
})
it('should call knightFight when data is true', () => {
const knight = new Knight().createKnight(true, null)
sinon.spy(knight, "knightFight")
assert(knight.knightFight.calledOnce)
})
})
As an aside, the private keyword is not valid JavaScript.
Related
I'm trying to define a simple assertion package in TypeScript so that assertions can be turned off during efficiency testing (and production eventually). Here's my attempt for a simple module:
let assertionsEnabled = true;
export function withAssertions<T>(val : boolean, body : () => T) : T {
const savedEnabled = assertionsEnabled;
try {
assertionsEnabled = val;
return body();
} finally {
assertionsEnabled = savedEnabled;
}
}
export function assert(condition : () => boolean, message ?: string) {
if (assertionsEnabled) {
if (!condition()) {
throw new Error("assertion failed" + (message ?? ""));
}
}
}
The problem is that both the Jest test and the class being tested each import this module and they seem to end up with two different assertionsEnabled variables. My test is encoded with
describe('building', () => {
withAssertions(false, () => {
...
});
});
and in the ADT, I have a bunch of assertions, but even though assertions are turned off in the Jest test, they are still on in the ADT. I thought modules were supposed to have a single instance. But obviously I'm doing something wrong.
I'm betting you have asynchronous stuff going on in your tests or stuff you instantiate as part of exporting from the module and it's happening before the jest stuff starts being executed.
Also, you might instead want to do a describeWithAssertion function instead, like so...
function describeWithAssertion(
ae: boolean,
title: string,
f: any // this should be specified better
) {
const prevAE = assertionsEnabled;
return describe(
title,
() => {
beforeEach(() => assertionsEnabled = ae);
afterEach(() => assertionsEnabled = prevAE);
f();
}
);
}
This way, even if f contains async functionality, jest is worrying about it, not you.
I'm trying to write an angular unit test for a function that has a dependency on an imported function - how can write a unit test that mocks the results of the imported function? The function I have is:
import { DependentMethod } from './dependentMethod';
export function doSomething() {
const dependentResults = DependentMethod(); // DependentMethod makes an http call and returns the result
return dependentResults;
}
In this case, I want to test the doSomething and mock the DependentMethod function. When I've tried to mock stuff before, I've used spy on class methods but I'm not sure how to handle it in this case. Any help would be greatly appreciated!
You can try something as below,
import { dependent } from './dependentLibrary';
describe('yourCoponent', () => {
let component: yourComponent;
let service : dependentService;
beforeEach(() => {
service = new dependent(null); // if your service has further dependency
component = new yourComponent(service);
});
it('should perform test', () => {
// Arrange part -->
spyOn(service, 'dependentMethod').and.callFake(() => {
return Observable.from([ [1,2,3] ]); // return your mock data
});
//Act part
component.ngOnInit();
//Assert
expect(component.testable.action).toBe(value);
});
I've tried to search for answer to this problem for some time now and I failed. So I decided to give it a try here. If there is a such question already and I missed it, I'm sorry for duplicate.
Assume I have this javascript module 'myValidator.js', where are two functions and one function calls the other one.
export const validate = (value) => {
if (!value.something) {
return false
}
// other tests like that
return true
}
export const processValue = (value) => {
if (!validate(value)) {
return null
}
// do some stuff with value and return something
}
Test for this like this.
I want to test the validate function, whether is behaves correctly. And then I have the processValue function that invokes the first one and returns some value when validation is ok or null.
import * as myValidator from './myValidator'
describe('myValidator', () => {
describe('validate', () => {
it('should return false when something not defined', () => {
...
}
}
describe('processValue', () => {
it('should return something when value is valid', () => {
const validateMock = jest.spyOn(myValidator, 'validate')
validateMock.mockImplementation(() => true)
expect(validate('something')).toEqual('somethingProcessed')
}
it('should return null when validation fails', () => {
const validateMock = jest.spyOn(myValidator, 'validate')
validateMock.mockImplementation(() => false)
expect(validate('somethingElse')).toEqual(null)
}
}
}
Now, the problem is that this doesn't actually work as processValue() actually calls the function inside the module, because of the closure I suppose. So the function is not mocked as only the reference in exports is changed to jest mock, I guess.
I have found a solution for this and inside the module to use
if (!exports.validate(value))
That works for the tests. However we use Webpack (v4) to build the app, so it transforms those exports into its own structure and then when the application is started, the exports is not defined and the code fails.
What's best solution to test this?
Sure I can do it with providing some valid and invalid value, for this simple case that would work, however I believe it should be tested separately.
Or is it better to not mock functions and call it through to avoid the problem I have or is there some way how to achieve this with JavaScript modules?
I finally found the answer to this question. It's actually in the the Jest examples project on GitHub.
// Copyright 2004-present Facebook. All Rights Reserved.
/**
* This file illustrates how to do a partial mock where a subset
* of a module's exports have been mocked and the rest
* keep their actual implementation.
*/
import defaultExport, {apple, strawberry} from '../fruit';
jest.mock('../fruit', () => {
const originalModule = jest.requireActual('../fruit');
const mockedModule = jest.genMockFromModule('../fruit');
//Mock the default export and named export 'apple'.
return {
...mockedModule,
...originalModule,
apple: 'mocked apple',
default: jest.fn(() => 'mocked fruit'),
};
});
it('does a partial mock', () => {
const defaultExportResult = defaultExport();
expect(defaultExportResult).toBe('mocked fruit');
expect(defaultExport).toHaveBeenCalled();
expect(apple).toBe('mocked apple');
expect(strawberry()).toBe('strawberry');
});
I have the following angularjs based component which works fine, but looking at test coverage anything after window.addEventListener('message', is not covered.
Should I mock the window object and provide my own implementation for addEventListener? or spy on it and check its been called?
my.component.controller.ts
export class MyComponentController {
constructor() {}
public theEventOccurred(e: any) {
let json = JSON.parse(e.data);
console.log(json.document);
}
public $onInit() {
window.addEventListener('message', (event) => {
this.theEventOccurred(event);
}, false);
}
}
my.component.spec.ts
describe('Component: my', () => {
let $componentController: angular.IComponentControllerService;
let scope: angular.IScope;
beforeEach(inject(
($rootScope: angular.IScope,
_$componentController_: angular.IComponentControllerService) => {
scope = $rootScope.$new();
$componentController = _$componentController_;
}));
describe('Controller: MyComponentController', () => {
it('should log json.document', () => {
let ctrl: any = $componentController('my', { $scope: scope });
ctrl.$onInit();
});
});
});
I think it's not a good pattern to access directly window or document object from the component code.
The better way, as I see, is to put window in a separate service and then just use a dependency injection to put the service into component.
Check this for example.
Then you can spy the methods of the service, or just inject a mock service in your tests.
I have been trying to unit test my angular custom service written in Typescript. The service reads a global variable defined on the Window object. I have made it promise, so that in future I can make a AJAX call to get this information. Here is my stripped down service: -
export class ProxyDetectiveService {
public static $inject = [
$window,
$q
];
constructor(private $window:ng.IWindowService,
private $q:ng.IQService) {
}
public getProxyUserObject = ():ng.IPromise<any> => {
this.log.debug('Proxy User Service called, to get proxy user details');
var deferred = this.$q.defer();
var proxyDetails = this.$window.portalObject;
deferred.resolve(proxyDetails);
return deferred.promise;
};
}
My unit Test Case: -
describe('Proxy Detective Service - Unit Test Cases', () => {
var proxyDetectiveService:any,
$window:ng.IWindowService;
beforeEach(() => {
module('myApp');
});
beforeEach(inject(($injector:ng.auto.IInjectorService, _$window_) => {
proxyDetectiveService = $injector.get('ProxyDetectiveService');
_$window_ = {
portalObject: {
proxyUserDetails: {
firstName: 'testFN',
lastName: 'testLN'
}
}
};
}));
it('should have proxy object defined', function () {
var promise = proxyDetectiveService.getProxyUserObject();
promise.then(function (response) {
expect(response).toBeDefined();
}).catch(function (response) {
expect(response).toBeUndefined();
});
});
});
Here are my questions: -
My Test case gets executed, but I dont see the mocked window object in the service?
My promise then or catch clause never gets executed?
Are there any better ways I can implement my service? My intention is to return a promise, in future I may use AJAX call.
You need to use $provide to provide a mocked value in a unit test:
beforeEach(() => {
module('myApp', ($provide) => {
$provide.value('$window', myMockedWindowObject)
});
});
You also need to call $rootScope.$apply() to move promises forward in unit tests.