From b9a7bb7b8362dc35e72e0cfbdc1bf8ee5fb111f6 Mon Sep 17 00:00:00 2001 From: johanblumenberg Date: Fri, 5 Jan 2018 01:38:47 +0100 Subject: [PATCH] Adding support for mocking interfaces --- src/Mock.ts | 14 ++++++++++---- src/Spy.ts | 2 +- src/ts-mockito.ts | 13 ++++++++++++- test/mocking.types.spec.ts | 37 ++++++++++++++++++++++++++++++++++++- 4 files changed, 59 insertions(+), 7 deletions(-) diff --git a/src/Mock.ts b/src/Mock.ts index 79d3f88..efdf4f0 100644 --- a/src/Mock.ts +++ b/src/Mock.ts @@ -18,7 +18,8 @@ export class Mocker { private mockableFunctionsFinder = new MockableFunctionsFinder(); private objectPropertyCodeRetriever = new ObjectPropertyCodeRetriever(); - constructor(private clazz: any, protected instance: any = {}) { + constructor(private clazz: any, intf: boolean, protected instance: any = {}) { + this.mock.__tsmockitoInterface = intf; this.mock.__tsmockitoInstance = this.instance; this.mock.__tsmockitoMocker = this; if (_.isObject(this.clazz) && _.isObject(this.instance)) { @@ -40,11 +41,16 @@ export class Mocker { get: (target: any, name: PropertyKey) => { const hasMethodStub = name in target; if (!hasMethodStub) { - this.createPropertyStub(name.toString()); - this.createInstancePropertyDescriptorListener(name.toString(), {}, this.clazz.prototype); + if (this.mock.__tsmockitoInterface) { + this.createMethodStub(name.toString()); + this.createInstanceActionListener(name.toString(), {}); + } else { + this.createPropertyStub(name.toString()); + this.createInstancePropertyDescriptorListener(name.toString(), {}, this.clazz.prototype); + } } return target[name]; - }, + } }; } diff --git a/src/Spy.ts b/src/Spy.ts index 2050fbe..7502db2 100644 --- a/src/Spy.ts +++ b/src/Spy.ts @@ -8,7 +8,7 @@ export class Spy extends Mocker { private realMethods: { [key: string]: RealMethod }; constructor(instance: any) { - super(instance.constructor, instance); + super(instance.constructor, false, instance); if (_.isObject(instance)) { this.processProperties(instance); diff --git a/src/ts-mockito.ts b/src/ts-mockito.ts index 12cd3e1..ad18dc6 100644 --- a/src/ts-mockito.ts +++ b/src/ts-mockito.ts @@ -32,7 +32,18 @@ export function spy(instanceToSpy: T): T { } export function mock(clazz: { new(...args: any[]): T; } | (Function & { prototype: T }) ): T { - return new Mocker(clazz).getMock(); + return new Mocker(clazz, false).getMock(); +} + +export function imock(): T { + class Empty {} + let mockedValue = new Mocker(Empty, true).getMock(); + + if (typeof Proxy === "undefined") { + return mockedValue; + } + var tsmockitoMocker = mockedValue.__tsmockitoMocker; + return new Proxy(mockedValue, tsmockitoMocker.createCatchAllHandlerForRemainingPropertiesWithoutGetters()); } export function verify(method: T): MethodStubVerificator { diff --git a/test/mocking.types.spec.ts b/test/mocking.types.spec.ts index cfd86df..b1a90a9 100644 --- a/test/mocking.types.spec.ts +++ b/test/mocking.types.spec.ts @@ -1,5 +1,5 @@ import {MethodToStub} from "../src/MethodToStub"; -import {instance, mock, when} from "../src/ts-mockito"; +import {instance, mock, imock, when, verify} from "../src/ts-mockito"; import {Bar} from "./utils/Bar"; describe("mocking", () => { @@ -152,6 +152,41 @@ describe("mocking", () => { }); }); + + describe("mocking an interface", () => { + let mockedFoo: SampleInterface; + let foo: SampleInterface; + + if (typeof Proxy !== "undefined") { + + it("can verify call count", () => { + // given + mockedFoo = imock(); + foo = instance(mockedFoo); + + // when + let result = foo.sampleMethod(); + + // then + verify(mockedFoo.sampleMethod()).called(); + expect(result).toBe(null); + }); + + it("can setup call actions", () => { + // given + mockedFoo = imock(); + foo = instance(mockedFoo); + when(mockedFoo.sampleMethod()).thenReturn(5); + + // when + let result = foo.sampleMethod(); + + // then + verify(mockedFoo.sampleMethod()).called(); + expect(result).toBe(5); + }); + } + }); }); abstract class SampleAbstractClass {