TypeMoq
Simple mocking library for JavaScript targeting TypeScript development. If you have used before a library like Moq then the syntax should look familiar, otherwise the examples below should hopefully provide enough information to get you started quickly.
Features
- Strongly typed
- Auto complete/intellisense support
- Static and dynamic mocking
- Mock objects, classes (with arguments), constructor functions and interfaces
- Control mock behavior
- Record and replay expectations
- Auto sandbox global objects and types
- Support ECMAScript 5 and 6
- Support node.js and browser
Installing
Release version
npm install typemoq
Or add this NuGet dependency to your project:
PM> Install-Package typemoq
The distribution directory should contain:
- Compiled JavaScript:
typemoq.js
and its minified version typemoq-min.js
- TypeScript definitions:
typemoq.d.ts
Development version
npm install https://github.com/florinn/typemoq
Node.js
TypeScript 1.6 and later
import * as TypeMoq from "typemoq";
TypeScript pre 1.6
TypeMoq = require("typemoq");
Browser
Include at the top of your script file:
import * as TypeMoq from "typemoq";
TypeMoq requires Lodash to run, so make sure to include it in your page along typemoq.js
:
<script src="https://unpkg.com/lodash"></script>
<script src="https://unpkg.com/typemoq"></script>
Also in your tsconfig.json
you need to set the module target as UMD
:
"compilerOptions": {
...
"module": "UMD",
...
}
At this point you should have access in your script to a global variable named TypeMoq
.
Usage
After importing TypeMoq into your project, the following types should be available:
### Create mocks
Static mocks
Static mocks can be created either from class types and constructor arguments or from existing objects, including function objects.
Using class types and constructor arguments
interface IBar {
value: string;
anyValue: any;
}
class Bar implements IBar {
value: string = '';
anyValue: any = undefined;
}
class Foo {
constructor(private _bar: IBar) { this._bar = _bar || new Bar(); }
get bar(): IBar { return this._bar; }
do(stringValue: string) { return 'Foo.do:' + stringValue; }
setBar(value: string) { this._bar.value = value; }
}
class GenericFoo<T> {
private _bar: T;
constructor(barCtor?: { new (): T }, public numberValue?: number) {
this._bar = new barCtor();
}
get bar(): T { return this._bar; }
do(stringValue: string) { return 'GenericFoo.do:' + stringValue + ': ' + this._bar.toString(); }
}
let mock: TypeMoq.IMock<Bar> = TypeMoq.Mock.ofType(Bar);
let mock: TypeMoq.IMock<IBar> = TypeMoq.Mock.ofType(Bar);
let mock: TypeMoq.IMock<IBar> = TypeMoq.Mock.ofType<IBar>(Bar);
let bar = new Bar();
let mock: TypeMoq.IMock<Foo> = TypeMoq.Mock.ofType(Foo, TypeMoq.MockBehavior.Loose, bar);
let mock: TypeMoq.IMock<GenericFoo<Bar>> = TypeMoq.Mock.ofType(GenericFoo, TypeMoq.MockBehavior.Loose, Bar, 999);
Using existing objects, including function objects
function someFunc() {
return "someFunc was called";
}
function someFuncWithArgs(a: any, b: any, c: any) {
return "someFuncWithArgs was called";
}
let bar = new Bar();
let mock: TypeMoq.IMock<Bar> = TypeMoq.Mock.ofInstance(bar);
let mock1: TypeMoq.IMock<() => string> = TypeMoq.Mock.ofInstance(someFunc);
let mock2: TypeMoq.IMock<(a: any, b: any, c: any)=>string> = TypeMoq.Mock.ofInstance(someFuncWithArgs);
Dynamic mocks
Dynamic mocking requires your runtime (browser or node.js) to support the Proxy
global object added in ECMAScript 6.
If Proxy
is not detected, TypeMoq is going to throw a MockException.
A dynamic mock is created by specifying a type parameter.
The following type parameters are supported:
let mock: TypeMoq.IMock<Function> = TypeMoq.Mock.ofType<Function>();
let mock: TypeMoq.IMock<Bar> = TypeMoq.Mock.ofType<Bar>();
let mock: TypeMoq.IMock<Foo> = TypeMoq.Mock.ofType<Foo>(undefined, TypeMoq.MockBehavior.Loose);
let mock: TypeMoq.IMock<typeof Bar> = TypeMoq.Mock.ofType<typeof Bar>();
let mock: TypeMoq.IMock<IBar> = TypeMoq.Mock.ofType<IBar>();
As opposed to static mocks, dynamic mocks have some limitations due to the absence of the underlying target instance:
- No partial mocking
- No embedded mocks passed as constructor arguments
- Properties return by default a
function
object and not undefined
interface IThing {
getA(a: string): string;
getB(b: number): number;
getC(): boolean;
valueA: string;
}
let mock: TypeMoq.IMock<IThing> = TypeMoq.Mock.ofType<IThing>();
expect(mock.object.getA("abc")).to.be.undefined;
expect(mock.object.getB(123)).to.be.undefined;
expect(mock.object.getC()).to.be.undefined;
expect(mock.object.valueA).to.be.a("function");
- Properties can be set to return any falsy value except
undefined
let mock: TypeMoq.IMock<IBar> = TypeMoq.Mock.ofType<IBar>();
mock.setup(x => x.anyValue).returns(() => null);
expect(mock.object.anyValue).to.be.null;
mock.reset();
mock.setup(x => x.anyValue).returns(() => 0);
expect(mock.object.anyValue).to.eq(0);
mock.reset();
mock.setup(x => x.anyValue).returns(() => undefined);
expect(mock.object.anyValue).to.be.a("function");
Note:
Mocks (created in any of the ways listed above) expose the actual mock object through the .object
property (that has the same type as the class or object being mocked).
### Setup mocks
Mocks allow to match functions, methods and properties and setup return callbacks or exceptions to throw.
setup
accepts a function (also referred as 'matcher') taking as input argument the type being mocked and as body the value/property/method (with arguments if that's the case) to match.
Parameter matchers
Matcher | Description |
---|
TypeMoq.It.isValue<T>(x: T) | Performs deep comparison against the provided object or basic value |
TypeMoq.It.isAny() | Matches any type |
TypeMoq.It.isAnyObject<T>(x: Ctor<T>) | Matches any object compatible with the provided type |
TypeMoq.It.isAnyString() | Matches any string |
TypeMoq.It.isAnyNumber() | Matches any number |
TypeMoq.It.is<T>(predicate: IFunc2<T, boolean>) | Performs comparison using the provided predicate |
Matching functions
let mock: TypeMoq.IMock<() => string> = TypeMoq.Mock.ofInstance(someFunc);
mock.setup(x => x()).returns(() => "At vero eos et accusamus");
let mock: TypeMoq.IMock<(a: any, b: any, c: any) => string> = TypeMoq.Mock.ofInstance(someFuncWithArgs);
mock.setup(x => x(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => "At vero eos et accusamus");
Matching methods
class Doer {
doVoid(): void { }
doNumber(n?: number): number { return n || 101; }
doString(s?: string): string { return s || 'xyz'; }
doObject(o?: Object): Object { return o || new Object(); }
doBar(b?: Bar): Bar { return b; }
}
let mock = TypeMoq.Mock.ofType(Doer);
mock.setup(x => x.doNumber());
mock.setup(x => x.doNumber(TypeMoq.It.isValue(321)));
mock.setup(x => x.doNumber(321));
mock.setup(x => x.doString(TypeMoq.It.isValue("abc")));
mock.setup(x => x.doString("abc"));
let bar = new Bar();
mock.setup(x => x.doObject(TypeMoq.It.isAnyObject(Bar)));
const anObject = {};
mock.setup(x => x(anObject)).returns(() => 123);
expect(mock.object(anObject)).to.eq(123);
mock.setup(x => x.doString(TypeMoq.It.isAnyString()));
mock.setup(x => x.doNumber(TypeMoq.It.isAnyNumber()));
let bar1 = new Bar();
let bar2 = new Bar();
mock.setup(x => x.doBar(TypeMoq.It.isAnyObject(Bar)));
let bar1 = new Bar();
bar1.value = "Ut enim ad minim veniam";
let bar2 = new Bar();
let mock = TypeMoq.Mock.ofType(Doer);
mock.setup(x => x.doBar(It.is((x: Bar) => x.value === "Ut enim ad minim veniam"))).returns(() => bar2);
To be able to match the static methods of some class, you would need to create a dynamic mock of the type of the class itself. E.g.
class Greeter {
private static _instance: Greeter | null;
static instance(): Greeter {
if (!this._instance) {
this._instance = new Greeter();
}
return this._instance;
}
greet(): string {
return 'Hello';
}
}
let greeter = Greeter.instance();
let mock: TypeMoq.IMock<typeof Greeter> = Typemoq.Mock.ofType<typeof Greeter>();
mock.setup(x => x.instance()).returns(() => greeter);
expect(mock.object.instance()).to.eq(greeter);
Matching properties
class FooWithPublicGetterAndSetter {
private _foo: string;
public get foo(): string { return this._foo; }
public set foo(value: string) { this._foo = value; }
}
let mock = TypeMoq.Mock.ofType(FooWithPublicGetterAndSetter);
mock.setup(x => x.foo);
mock.object.foo = "Lorem ipsum dolor sit amet";
mock.verify(x => x.foo = It.isValue("Lorem ipsum dolor sit amet"), Times.atLeastOnce());
Note:
To be able to match a property make sure the property is initialized.
Otherwise the TypeScript compiler will omit the uninitialized property from the emitted JavaScript and hence TypeMoq will throw a MockException with an 'invalid setup expression' message.
class Baz {
value: string = '';
anyValue: any;
}
let mock = TypeMoq.Mock.ofType(Baz);
mock.setup(x => x.value);
mock.setup(x => x.anyValue);
Attaching return callbacks
The callback attached to .returns
has the same signature as the matching function/method.
Also the callback gets called with the arguments passed to the matching function/method and it must have the same return type, making possible the following:
mock.setup(x => x.doString("abc")).returns((s: string) => s.toUpperCase());
Attaching exceptions to throw
mock.setup(...).throws(new CustomException());
Attach callbacks
Attached callbacks are called before the .returns
callback or .throws
get called, and they have similar signature and behavior to .returns
callbacks.
let mock = TypeMoq.Mock.ofType(Doer);
let called1, called2 = false;
let numberArg: number;
mock.setup(x => x.doString(TypeMoq.It.isAnyString())).callback(() => called1 = true).returns(s => s.toUpperCase());
mock.setup(x => x.doNumber(TypeMoq.It.isAnyNumber())).callback(n => { numberArg = n; called2 = true; }).returns(n => n + 1);
Record and replay
Mocks allow to "record" and "replay" one or more setups for the same matching function, method or property.
- If a single setup is recorded then at replay it is always executed:
let mock = TypeMoq.Mock.ofInstance(() => -1);
mock.setup(x => x()).returns(() => 0);
expect(mock.object()).to.eq(0);
expect(mock.object()).to.eq(0);
expect(mock.object()).to.eq(0);
- If more setups are recorded then at replay they are executed in the order of registration:
let mock = TypeMoq.Mock.ofInstance(() => -1);
mock.setup(x => x()).returns(() => 0);
mock.setup(x => x()).returns(() => 1);
mock.setup(x => x()).returns(() => 2);
expect(mock.object()).to.eq(0);
expect(mock.object()).to.eq(1);
expect(mock.object()).to.eq(2);
expect(mock.object()).to.eq(undefined);
In the latter case, when there are no more recorded setups left to play, the mock starts returning default values or raises MockException if MockBehavior.Strict
(see Control mock behavior).
Reset mocks
Calling .reset()
on a mock returns the mock to its initial state by removing any previous setups.
### Control mock behavior
Using MockBehavior
When creating a mock, you may specify a behavior value such as:
MockBehavior.Loose
(default) - never throws when no corresponding setup is found and just returns default valuesMockBehavior.Strict
- raises exceptions for anything that doesn't have a corresponding setup
let mock = TypeMoq.Mock.ofType(Doer, TypeMoq.MockBehavior.Strict);
Partial mocking
When the mock property callBase
is set to true
, if there's no overriding setup the mock invokes the object being mocked.
mock.callBase = true;
The default value of callBase
is false
, so by default when there's no overriding setup the mock returns undefined
.
### Verify expectations
Expectations can be verified either one by one or all at once by marking matchers as verifiable.
Expectations
Expectation | Description |
---|
TypeMoq.Times.exactly(n: number) | Called exactly n times |
TypeMoq.Times.never() | Never called |
TypeMoq.Times.once() | Called once |
TypeMoq.Times.atLeastOnce() | Called at least once (default value) |
TypeMoq.Times.atMostOnce() | Called at most once |
Verify expectations one by one
To verify an expectation you can use the verify
method and specify a matching function and an expectation.
let mock: TypeMoq.IMock<() => string> = TypeMoq.Mock.ofInstance(someFunc);
mock.object();
mock.verify(x => x(), TypeMoq.Times.atLeastOnce());
let mock: TypeMoq.IMock<(a: any, b: any, c: any) => string> = TypeMoq.Mock.ofInstance(someFuncWithArgs);
mock.object(1, 2, 3);
mock.verify(x => x(TypeMoq.It.isAnyNumber(), TypeMoq.It.isAnyNumber(), TypeMoq.It.isAnyNumber()), TypeMoq.Times.atLeastOnce());
let mock = TypeMoq.Mock.ofType(Doer);
mock.object.doVoid();
mock.verify(x => x.doVoid(), TypeMoq.Times.atLeastOnce());
let mock = TypeMoq.Mock.ofType(Doer);
mock.object.doString("Lorem ipsum dolor sit amet");
mock.verify(x => x.doString(TypeMoq.It.isValue("Lorem ipsum dolor sit amet")), TypeMoq.Times.atLeastOnce());
let mock = TypeMoq.Mock.ofType(Bar);
mock.object.value;
mock.verify(x => x.value, TypeMoq.Times.atLeastOnce());
let mock = TypeMoq.Mock.ofType(Bar);
mock.object.value = "Lorem ipsum dolor sit amet";
mock.verify(x => x.value = TypeMoq.It.isValue("Lorem ipsum dolor sit amet"), TypeMoq.Times.atLeastOnce());
Note:
- When constructing a mock, it is allowed to pass mock objects as arguments and later verify expectations on them. E.g.:
let mockBar = TypeMoq.Mock.ofType(Bar);
let mockFoo = TypeMoq.Mock.ofType(Foo, TypeMoq.MockBehavior.Loose, mockBar.object);
mockFoo.callBase = true;
mockFoo.object.setBar("Lorem ipsum dolor sit amet");
mockBar.verify(x => x.value = TypeMoq.It.isValue("Lorem ipsum dolor sit amet"), TypeMoq.Times.atLeastOnce());
- For static mocks, TypeMoq is able to verify any inner calls inside regular functions but not inside lambda ones. E.g.:
class FooBar {
register(): void {
this.canExecute();
}
registerLambda = () => {
this.canExecute();
}
canExecute(): void {
console.log("FooBar.canExecute() was called");
}
}
let mock: TypeMoq.IMock<FooBar> = TypeMoq.Mock.ofType(FooBar);
mock.callBase = true;
mock.object.register();
mock.object.registerLambda();
mock.verify(x => x.canExecute(), Times.once());
Verify all expectations at once
Instead of verifying one expectation at a time, you may specify the expectation at setup time by calling verifiable(times: Times)
and then verifyAll()
to check all expectations.
mock.setup(x => x.doNumber(999)).verifiable();
mock.setup(x => x.doString(It.isAny())).verifiable(Times.exactly(2));
mock.setup(x => x.doVoid()).verifiable(Times.atMostOnce());
mock.object.doVoid();
mock.object.doString("Lorem ipsum dolor sit amet");
mock.object.doString("Ut enim ad minim veniam");
mock.object.doNumber(999);
mock.verifyAll();
The default value of the times
param is Times.atLeastOnce()
.
Verify expectation invocation order
Expectation invocation order | Description |
---|
TypeMoq.ExpectedCallType.InAnyOrder | Only call count considered (default value) |
TypeMoq.ExpectedCallType.InSequence | Both call count and order considered |
let mock = Mock.ofInstance((x: number) => { });
mock.setup(x => x(1)).verifiable(Times.once(), ExpectedCallType.InSequence);
mock.setup(x => x(2)).verifiable(Times.once(), ExpectedCallType.InSequence);
mock.object(2);
mock.object(1);
mock.verifyAll();
### Create global mocks
Static global mocks
Static global mocks are created by specifying a class type or an existing object, similar to regular static mocks.
You may also specify a container object for the type/object being mocked.
For browsers the top global object is the window
object, which is the default container
value in TypeMoq.GlobalMock
.
For node.js the top global object is the global
object.
Using class types
interface IGlobalBar {
value: string;
}
class GlobalBar implements IGlobalBar {
value: string = '';
}
let mock: TypeMoq.IGlobalMock<GlobalBar> = TypeMoq.GlobalMock.ofType(GlobalBar, global);
let mock: TypeMoq.IGlobalMock<IGlobalBar> = TypeMoq.GlobalMock.ofType(GlobalBar, global);
let mock: TypeMoq.IGlobalMock<IGlobalBar> = TypeMoq.GlobalMock.ofType<IGlobalBar>(GlobalBar, global);
let mock = TypeMoq.GlobalMock.ofType(XMLHttpRequest, global);
Using existing objects, including function objects
When creating mock instances out of global objects (such as window.localStorage
), you should provide the name of the global object ("localStorage" in this case) as the second parameter.
let bar = new Bar();
let foo = new Foo(bar);
let mock: TypeMoq.IGlobalMock<Foo> = TypeMoq.GlobalMock.ofInstance(foo);
let foo = new GenericFoo(Bar);
let mock: TypeMoq.IGlobalMock<GenericFoo<Bar>> = TypeMoq.GlobalMock.ofInstance(foo);
let bar = new GlobalBar();
let mock: TypeMoq.IGlobalMock<GlobalBar> = TypeMoq.GlobalMock.ofInstance(bar);
let mock1: TypeMoq.IGlobalMock<() => string> = TypeMoq.GlobalMock.ofInstance(someGlobalFunc);
let mock2: TypeMoq.IGlobalMock<(a: any, b: any, c: any) => string> = TypeMoq.GlobalMock.ofInstance(someGlobalFuncWithArgs);
let mock = TypeMoq.GlobalMock.ofInstance(localStorage, "localStorage");
Note:
Due to browser security limitations, global mocks created by specifying class type cannot have constructor arguments
Dynamic global mocks
Dynamic global mocks are created by specifying a type parameter and the name of the global object as the first constructor argument.
let mock: TypeMoq.IGlobalMock<GlobalBar> = TypeMoq.GlobalMock.ofType2<GlobalBar>("GlobalBar", global);
let mock: TypeMoq.IGlobalMock<IGlobalBar> = TypeMoq.GlobalMock.ofType2<IGlobalBar>("IGlobalBar", global);
let mock = TypeMoq.GlobalMock.ofType2<XMLHttpRequest>("XMLHttpRequest", global);
Compared to static global mocks, dynamic global mocks suffer from the same limitations as regular dynamic mocks.
### Auto sandbox global mocks
Replacing and restoring global class types and objects is done automagically by combining global mocks with global scopes.
function someGlobalFunc() {
return "someGlobalFunc was called";
}
function someGlobalFuncWithArgs(a: any, b: any, c: any) {
return "someGlobalFuncWithArgs was called";
}
let mock = TypeMoq.GlobalMock.ofInstance(someGlobalFunc);
TypeMoq.GlobalScope.using(mock).with(() => {
someGlobalFunc();
someGlobalFunc();
});
let mock = TypeMoq.GlobalMock.ofInstance(someGlobalFuncWithArgs);
TypeMoq.GlobalScope.using(mock).with(() => {
someGlobalFuncWithArgs(1,2,3);
someGlobalFuncWithArgs("1","2","3");
someGlobalFuncWithArgs(1, 2, 3);
);
let mock = TypeMoq.GlobalMock.ofType(GlobalBar);
TypeMoq.GlobalScope.using(mock).with(() => {
let bar1 = new GlobalBar();
bar1.value;
bar1.value;
});
let mock = TypeMoq.GlobalMock.ofType(XMLHttpRequest);
TypeMoq.GlobalScope.using(mock).with(() => {
let xhr1 = new XMLHttpRequest();
xhr1.open("GET", "http://www.typescriptlang.org", true);
xhr1.send();
mock.verify(x => x.send(), TypeMoq.Times.exactly(1));
});
let xhr2 = new XMLHttpRequest();
xhr2.open("GET", "http://www.typescriptlang.org", true);
xhr2.send();
mock.verify(x => x.send(), TypeMoq.Times.exactly(1));
let mock = TypeMoq.GlobalMock.ofInstance(localStorage, "localStorage");
mock.setup(x => x.getItem(TypeMoq.It.isAnyString())).returns((key: string) => "[]");
TypeMoq.GlobalScope.using(mock).with(() => {
expect(localStorage.getItem("xyz")).to.eq("[]");
});
localStorage.setItem("xyz", "Lorem ipsum dolor sit amet");
expect(localStorage.getItem("xyz")).to.eq("Lorem ipsum dolor sit amet");
Note:
Inside the scope of a TypeMoq.GlobalScope, when constructing objects from global functions/class types which are being replaced by mocks, the constructor always returns the mocked object (of corresponding type) passed in as argument to the TypeMoq.GlobalScope.using
function