Skip to content

Instantly share code, notes, and snippets.

@marcorinck
Last active May 2, 2020 04:01
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marcorinck/8d242cd4e08374016423b115b3b1366a to your computer and use it in GitHub Desktop.
Save marcorinck/8d242cd4e08374016423b115b3b1366a to your computer and use it in GitHub Desktop.
semi-automatic mock generation in TypeScript (uses Jest as testing framework)
import {clearMocks, Mock, mockClass, initMocks} from "mockclass";
import {ErrorService} from "../components/http/error.service";
describe('MyService', () => {
//use as a decorator in an empty holder class
class Mocks extends MockHolder {
@Mock(ErrorService)
errorService: ErrorService;
}
const mocks = initMocks("mocks", Mocks);
//use as a function
const errorServiceMock = mockClass<ErrorService>(ErrorService);
let service: MyService;
beforeEach(() => {
//use only one of these
service = new MyService(mocks.errorService);
service = new MyService(errorServiceMock);
clearMocks(); // mocks are reused between test cases and suites and need to be cleared
});
it('should do something', () => {
//use only one of these
asMock(errorServiceMock.log).mockReturnValue(null);
asMock(mocks.errorService.log).mockReturnValue(null);
service.doSomething();
//use only one of these
expect(errorServiceMock.log).not.toHaveBeenCalled();
expect(mocks.errorService.log).not.toHaveBeenCalled();
});
});
import Mock = jest.Mock;
const mockedClazzes = [];
export function mockClass<C>(clazz: any): C {
const keys = describeClass(clazz);
const mock = <C>{};
for (const key of keys) {
if (key !== "constructor") {
try {
const name = clazz.name + "." + key;
const type = typeof clazz.prototype[key];
if (type && type === 'function') {
mock[key] = jest.fn().mockName(name);
} else {
mock[key] = clazz.prototype[key];
}
} catch (e) {
}
}
}
mockedClazzes.push(mock);
return mock;
}
export function asMock(func: Function) {
return (<Mock>func);
}
function describeClass(clazz: any): string[] {
const proto = clazz.prototype;
const props = [];
if (proto) {
for (let prop in proto) {
if (proto.hasOwnProperty(prop)) {
props.push(prop);
}
}
}
return props;
}
export function clearMocks() {
for (const mockedClazz of mockedClazzes) {
for (let prop in mockedClazz) {
if (mockedClazz.hasOwnProperty(prop)) {
const member = mockedClazz[prop];
if (member.mockClear) {
member.mockClear();
}
}
}
}
}
export abstract class MockHolder {
name: string;
constructor(name: string) {
this.name = name;
}
}
export function initMocks<T extends MockHolder>(name: string, constructorFn: new (name: string) => T) {
return new constructorFn(name);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment