to-mock
v1.6.2
Published
The utility to mock class and objects. You can use mocked classes and objects for your unit and integration tests
Downloads
55,990
Maintainers
Readme
to-mock
The to-mock module help you with creating mocked classes and objects. So your tests are up to date with your defined classes because you don't have to keep mocks or interface for your tests. Then you can creating the unit tests for interface and not for implementation detail, your tests are more isolated and you can easy creating real unit tests.
The javascript to-mock module can be used with any test framework like jest, ava, tape, jasmine, mocha and others. Even you may use it for mocking in typescript. Those are other benefits for your unit tests because you can change test framework or language.
You can mock Date, RegExp and other native object.
Installation
You can add the to-mock to your project or testing tools using npm:
npm i to-mock --save-dev
Examples
- Jasmine - example with jasmine and toMockedInstance
- Jest/Typescript - example with jest and typescript
- AVA - example with ava and self testing
- Best practice - example with setting to-mock module for jest framework
API
Usage
The library is designed to be used in ES2015 environment. For older node <6 you must use babel and for older browser use browserify with babel.
// MyArray.js
export default class MyArray {
constructor(array) {
this.array = array.slice();
}
clone() {
return this.array.slice();
}
}
//MyArraySpec.js
import MyArray from './MyArray';
import toMock from 'to-mock';
describe('Your spec', () => {
// The MyArray class is not modified
const MockedMyArray = toMock(MyArray);
//class MockedMyArray {
// constructor() {}
// clone() {}
//}
const mockedInstance = new MockedMyArray();
it('is instance of MyArray', () => {
expect(mockedInstance instanceof MyArray).toBeTruthy();
});
it('method not throw Error', () => {
expect(() => mockedInstance.clone()).not.toThrow();
});
});
Mock native object
Example with overriding native Date object.
//MyDateSpec.js
import toMock from 'to-mock';
describe('Your spec', () => {
const MockedDate = toMock(Date);
const RealDate = Date;
beforeEach(() => {
Date = MockedDate;
});
afterEach(() => {
Date = RealDate;
};)
it('you can mock date', () => {
spyOn(MockedDate, 'now').and.returnValue(1);
expect(Date.now()).toEqual(1);
});
});
toMockedInstance
Sometimes you want to working with mocked instance which will be defined some default values. You can use of course toMock function for that but better solution is use toMockedInstance function.
//MyDateSpec.js
import toMock, { toMockedInstance } from 'to-mock';
describe('Your spec', () => {
it('you can create mocked instance of date', () => {
//let MockedDate = toMock(Date);
//let date = new MockedDate();
//let dateWithDefault = Object.assign(
// date,
// { getTime: () => 1 }
//);
const dateWithDefault = toMockedInstance(
Date,
{ getTime: () => 1 }
);
expect(dateWithDefault.getTime()).toEqual(1);
});
});
setGlobalKeepUnmock
You want to working with unmocked methods and properties in very rare use case. For that case you can used globalKeepUnmock method or defined keepUnmock callback as other argument.
//MyDateSpec.js
import toMock, { toMockedInstance, setGlobalKeepUnmock } from 'to-mock';
describe('Your spec', () => {
it('you can create mocked instance of date', () => {
function keepUnmock({ property, descriptor, original, mock }) {
return property === 'getDay';
}
//let MockedDate = toMock(Date, keepUnmock);
//or
//let MockedDate = toMock(Date);
//setGlobalKeepUnmock(keepUnmock);
//let date = new MockedDate();
//let dateWithDefault = Object.assign(
// date,
// { getTime: () => 1 }
//);
let dateWithDefault = toMockedInstance(
Date,
{ getTime: () => 1 },
keepUnmock
);
let dayFromMock = Reflect.apply(
dateWithDefault.getDay,
new Date(),
[]
);
let dayFromDate = new Date().getDay();
expect(dateWithDefault.getTime()).toEqual(1);
expect(dayFromMock === dateFromDate).toEqual(true);
});
});
setGlobalMockMethod
You can define a specific mock function used for all method mocks. This way, you can replace all these methods with jest.fn, or any other mock method, depending on your testing framework.
//MyDateSpec.js
import { toMockedInstance, setGlobalMockMethod } from 'to-mock';
describe('Your spec', () => {
it('you can create mocked instance of date', () => {
setGlobalMockMethod(jest.fn);
let date = toMockedInstance(Date);
date.getTime();
// You can use all jest.fn() related methods now
expect(date.getTime).toHaveBeenCalled();
});
});
Typescript
Sometimes you need mock all methods in file and sometimes you need original method for some use cases. For example: Jest have method mockFn.mockRestore for restoring original method but it throws error for typescript. Luckily to-mock module will help you. You can see source code
//indexSpec.ts
import { setGlobalMockMethod, toMockedInstance } from 'to-mock';
import * as utils from '../utils';
//jest.mock('../utils');
//utils.once.mockRestore(); // throw Error in Typescript
jest.mock('../utils', () => {
const original = jest.requireActual('../utils');
setGlobalMockMethod(jest.fn);
return toMockedInstance(
original,
{ __original__: original },
({ property }) => property === 'once'
);
});
Best practice
We use to-mock module for unit tests and integration tests in large applications. We share you our setup file for jest framework which you can configure through setupFiles.
// setupJest.js
import {
objectKeepUnmock,
setGlobalKeepUnmock,
setGlobalMockMethod
} from 'to-mock';
// every method is replaced to jest.fn()
setGlobalMockMethod(jest.fn);
// native object method keep unmock
setGlobalKeepUnmock(objectKeepUnmock);
// *Spec.js
import { toMockedInstance } from 'to-mock';
// we use toMockedInstance almost everywhere
Contributing
Contributing to this repository is done via Pull-Requests. Any commit that you make must follow simple rules that are automatically validated upon committing.
- type of change (
build
,ci
,chore
,docs
,feat
,fix
,perf
,refactor
,revert
,style
,test
) - scope of change in brackets
( ... )
. This should be one-word description of what part of the repository you've changed. - colon
:
- message (lower-case)
fix(iframe): message
feat(loader): message
To simplify this process you can use npm run commit
command that will interactively prompt for details and will also run linter before you commit. For more information see commitizen/cz-cli repository.