Last active
May 2, 2020 04:01
-
-
Save marcorinck/8d242cd4e08374016423b115b3b1366a to your computer and use it in GitHub Desktop.
semi-automatic mock generation in TypeScript (uses Jest as testing framework)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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