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 versiontypemoq-min.js
- TypeScript definitions:
typemoq.d.ts
Development version
npm install https://github.com/florinn/typemoq
Node.js
TypeScript 1.6 and later
;
TypeScript pre 1.6
/// TypeMoq = require"typemoq";
Browser
Include at the top of your script file:
/// ;
TypeMoq requires some dependencies to run, so make sure to include them in your page before typemoq.js
:
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:
Type | Description |
---|---|
TypeMoq.Mock | Used for creating 'regular' mocks (see Create mocks and Setup mocks) |
TypeMoq.MockBehavior | Used to specify how the mock should act when no expectations are defined (see Control mock behavior) |
TypeMoq.It | Helper for matching arguments (see Setup mocks and Verify expectations) |
TypeMoq.Times | Helper for performing verification (see Verify expectations) |
TypeMoq.GlobalMock | Used to create 'global' mocks corresponding to global objects (see Create global mocks) |
TypeMoq.GlobalScope | Used to create an execution context that makes use of any specified 'global' mocks (see Auto sandbox global mocks) |
TypeMoq.MockException | Exception thrown internally containing debug info |
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
method TypeMoq.Mock.ofTypetargetConstructor?: , behavior?: TypeMoq.MockBehavior, shouldOverrideTarget?: boolean, ...targetConstructorArgs: any: TypeMoq.IMock<T> method TypeMoq.Mock.ofType2targetConstructor: , targetConstructorArgs: any, behavior?: TypeMoq.MockBehavior, shouldOverrideTarget?: boolean: TypeMoq.IMock<T>
- targetConstructor - target constructor type
- ...targetConstructorArgs - target constructor args
- behavior - mock behavior (see Control mock behavior)
- shouldOverrideTarget - override target properties (see Override target properties)
Note: During the creation of the static mock, the target object is being instantiated as a regular JavaScript object by executing the target constructor with any provided constructor args
Examples:
// Using class as constructor parameter; // Using class as constructor parameter and casting result to interface; // Using interface as type variable and class as constructor parameter; // Using class as constructor parameter and constructor arguments;; // Using a generic class as constructor parameter and constructor arguments;
Using existing objects, including function objects
method TypeMoq.Mock.ofInstance targetInstance: T, behavior?: TypeMoq.MockBehavior, shouldOverrideTarget?: boolean: TypeMoq.IMock<T>
- targetInstance - target object
- behavior - mock behavior (see Control mock behavior)
- shouldOverrideTarget - override target properties (see Override target properties)
Note: To create the static mock, the provided target object is replaced by a deep clone which is accesible through the .target
property of the resulting mock object
Examples:
// From an existing object;; // Or from function objects;;
Dynamic mocks
Important: Dynamic mocking requires the 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 just a type parameter and some optional args:
method TypeMoq.Mock.ofTypetargetConstructor?: , behavior?: TypeMoq.MockBehavior, shouldOverrideTarget?: boolean: TypeMoq.IMock<T>
- targetConstructor - always
undefined
for dynamic mocks - behavior - mock behavior (see Control mock behavior)
- shouldOverrideTarget - override target properties (see Override target properties)
Note: While creating the dynamic mock, the target object is not instantiated by executing the constructor of the provided type parameter
The following type parameters are supported:
Function
(as the type of a function object)
// Using Function as type parameter;
- a class type
// Using the 'instance' side of the class as type parameter; // Specifying mock behavior;
- a constructor function
// Using the 'static' side of the class as type parameter;
- an interface type
// Using an interface as type parameter;
As opposed to static mocks, dynamic mocks have some limitations:
- No partial mocking
- No embedded mocks passed as constructor arguments
- Properties return by default a
function
object and notundefined
; expectmock.object.getA"abc".to.be.undefined;expectmock.object.getB123.to.be.undefined;expectmock.object.getC.to.be.undefined;expectmock.object.valueA.to.be.a"function";
As a workaround you may set the property to return undefined
:
mock.setupx.valueA.returnsundefined; expectmock.object.valueA.to.be.undefined;
This limitation also impacts the scenario where a mocked object is passed to Promise.resolve
. To be able to handle such scenario, the mocked object must be set as a thenable (i.e. has a "then" method) by returning undefined
or another value:
mock.setupx.then.returnsundefined; Promise.resolvemock.object .then;
Mocks type
Mocks (created in any of the ways listed above) have the type IMock<T>
and expose a couple important properties:
(property) TypeMoq.IMock<T>.object: T
- the actual mock object (that has the same type T as the class or object being mocked)(property) TypeMoq.IMock<T>.target: T
- the underlying object being mocked
Setup mocks
Mocks allow to match functions, methods and properties and setup return callbacks or exceptions to throw.
method TypeMoq.IMock<T>.setup expression:TResult: TypeMoq.MethodCallReturn<T, TResult>
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.isObjectWith<T>(x: Object) |
Performs partial deep comparison against the provided object |
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 |
If no matcher is specified then an implicit matcher is considered that performs strict equality deep comparison, equivalent to TypeMoq.It.is(x => _.isEqual(x, a))
.
Matching functions
// Match a no args function;mock.setupx.returns"At vero eos et accusamus"; // Match a function with args;mock.setupxTypeMoq.It.isAny, TypeMoq.It.isAny, TypeMoq.It.isAny.returns"At vero eos et accusamus";
Matching methods
; // Match a no args methodmock.setupx.doNumber; // Match a method with explicit number value paramsmock.setupx.doNumberTypeMoq.It.isValue321; // Match a method with implicit number value paramsmock.setupx.doNumber321; // Match a method with explicit string value paramsmock.setupx.doStringTypeMoq.It.isValue"abc"; // Match a method with implicit string value paramsmock.setupx.doString"abc"; // Match a method with object value params;mock.setupx.doObjectTypeMoq.It.isAnyObjectBar; // Match a method with implicit object value params;mock.setupxanObject.returns123;expectmock.objectanObject.to.eq123; // Match a method with any string paramsmock.setupx.doStringTypeMoq.It.isAnyString; // Match a method with any number paramsmock.setupx.doNumberTypeMoq.It.isAnyNumber; // Match a method with any interface/class paramsmock.setupx.doBarTypeMoq.It.isAnyObjectBar; // Match a method by a param predicate ;bar1.value = "Ut enim ad minim veniam";;; mock.setupx.doBarTypeMoq.It.isx.value === "Ut enim ad minim veniam".returnsbar2;
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.
;; mock.setupx.instance.returnsgreeter; expectmock.object.instance.to.eqgreeter;
Matching properties
// Match a property getter;mock.setupx.foo; // Match a property settermock.object.foo = "Lorem ipsum dolor sit amet";mock.verifyx.foo = TypeMoq.It.isValue"Lorem ipsum dolor sit amet", Times.atLeastOnce;
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.
;mock.setupx.value; // OKmock.setupx.anyValue; // throws MockException - invalid setup expression
Matching objects
; // Match object deeplymock.setupx.fooTypeMoq.It.isValue; // Match object partiallymock.setupx.fooTypeMoq.It.isObjectWith;
For the predicate based matcher, TypeMoq.It.is<T>(predicate: IFunc2<T, boolean>)
, the argument of the predicate is a deep clone of the target argument, thus for doing object equality comparison, ===
should be replaced by _.isEqual
.
;; // Wrong way of doing strict object comparisonservice.setupx.getBeansTypeMoq.It.isx === beanParams.returns'success';expectservice.object.getBeansbeanParams.to.not.eq'success'; // Right way of doing strict object comparisonservice.setupx.getBeansTypeMoq.It.is_.isEqualx, beanParams.returns'success';service.setupx.getBeansbeanParams.returns'success'; // Short form equivalent to the explicit form aboveexpectservice.object.getBeansbeanParams.to.eq'success';
Attaching return callbacks
method TypeMoq.IReturns<T, TResult>.returns valueFunction:TResult: TypeMoq.IReturnsResult<T>
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.setupx.doString"abc".returnss.toUpperCase;
Attaching exceptions to throw
method TypeMoq.IThrows.throwsexception: T: TypeMoq.IThrowsResult
Example:
mock.setup....throwsnew CustomException;
Attach callbacks
method TypeMoq.ICallback<T, TResult>.callback action:void: TypeMoq.IReturnsThrows<T, TResult> method TypeMoq.ICallback<T, TResult>.callback action:void: TypeMoq.IReturnsThrows<T, TResult>
Attached callbacks are called before the .returns
callback or .throws
get called, and they have similar signature and behavior to .returns
callbacks.
Examples:
;;; mock.setupx.doStringTypeMoq.It.isAnyString.callbackcalled1 = true.returnss.toUpperCase;mock.setupx.doNumberTypeMoq.It.isAnyNumber.callback.returnsn + 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:
; // recordmock.setupx.returns0; // replayexpectmock.object.to.eq0;expectmock.object.to.eq0;expectmock.object.to.eq0;
- If more setups are recorded then at replay they are executed in the order of registration:
; // recordmock.setupx.returns0;mock.setupx.returns1;mock.setupx.returns2; // replayexpectmock.object.to.eq0;expectmock.object.to.eq1;expectmock.object.to.eq2;expectmock.object.to.equndefined;
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
method TypeMoq.IMock<T>.reset: void
Calling .reset()
on a mock returns the mock to its initial state by removing any previous setups.
Control mock behavior
Using MockBehavior
At mock creation, use the optional behavior
argument with value:
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
;
Partial mocking
property TypeMoq.IMock<T>.callBase: boolean
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
.
Override target properties
At mock creation, use the optional shouldOverrideTarget
argument with value:
true
(default) - mock setups are going to be applied to the target objectfalse
- mock setups are not going to be applied to the target object
To be able to use the target object inside .returns
, you need to choose not to override the target properties:
;; mock.setupx.getValue.returnsmock.target.getValue; expectmock.object.getValue.equal100;
Verify expectations
method TypeMoq.IVerifies.verifiabletimes?: TypeMoq.Times: void
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.atLeast(n: number) |
Called at least n times |
TypeMoq.Times.atMost(n: number) |
Called at most n times |
TypeMoq.Times.atLeastOnce() |
Called at least once (default value) |
TypeMoq.Times.atMostOnce() |
Called at most once |
Verify expectations one by one
method TypeMoq.IMock<T>.verify expression:TResult, times: TypeMoq.Times: void
To verify an expectation you can use the verify
method and specify a matching function and an expectation.
Examples:
// Verify that a no args function was called at least once;mock.object;mock.verifyx, TypeMoq.Times.atLeastOnce; // Verify that a function with args was called at least once;mock.object1, 2, 3;mock.verifyxTypeMoq.It.isAnyNumber, TypeMoq.It.isAnyNumber, TypeMoq.It.isAnyNumber, TypeMoq.Times.atLeastOnce; // Verify that no args method was called at least once;mock.object.doVoid;mock.verifyx.doVoid, TypeMoq.Times.atLeastOnce; // Verify that method with params was called at least once;mock.object.doString"Lorem ipsum dolor sit amet";mock.verifyx.doStringTypeMoq.It.isValue"Lorem ipsum dolor sit amet", TypeMoq.Times.atLeastOnce; // Verify that value getter was called at least once;mock.object.value;mock.verifyx.value, TypeMoq.Times.atLeastOnce; // Verify that value setter was called at least once;mock.object.value = "Lorem ipsum dolor sit amet";mock.verifyx.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.:
;;mockFoo.callBase = true; mockFoo.object.setBar"Lorem ipsum dolor sit amet"; mockBar.verifyx.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.:
;mock.callBase = true; mock.object.register;mock.object.registerLambda; // Function calls cannot be verified inside a lambda mock.verifyx.canExecute, TypeMoq.Times.once;
Verify all expectations at once
method TypeMoq.IMock<T>.verifyAll: void
Instead of verifying one expectation at a time, you may specify the expectation at setup time by calling verifiable(times: TypeMoq.Times)
and then verifyAll()
to check all expectations.
The default value of the times
parameter is equal to TypeMoq.Times.once()
.
mock.setupx.doNumber999.verifiable; // implicitly TypeMoq.Times.once()mock.setupx.doStringTypeMoq.It.isAny.verifiableTypeMoq.Times.exactly2;mock.setupx.doVoid.verifiableTypeMoq.Times.atMostOnce; mock.object.doVoid;mock.object.doString"Lorem ipsum dolor sit amet";mock.object.doString"Ut enim ad minim veniam";mock.object.doNumber999; mock.verifyAll;
When mock behavior is TypeMoq.MockBehavior.Strict
, every call to .setup()
automatically calls .verifiable()
behind the scenes, as the default.
; mock.setupx.doNumber999; // implicitly TypeMoq.Times.once()mock.setupx.doVoid.verifiableTypeMoq.Times.atMostOnce; mock.object.doVoid;mock.object.doNumber999; mock.verifyAll;
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 |
; mock.setupx1.verifiableTypeMoq.Times.once, TypeMoq.ExpectedCallType.InSequence;mock.setupx2.verifiableTypeMoq.Times.once, TypeMoq.ExpectedCallType.InSequence; mock.object2;mock.object1; mock.verifyAll; // it should throw MockException
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
method TypeMoq.GlobalMock.ofTypetargetConstructor: , container?: Object, behavior?: TypeMoq.MockBehavior: TypeMoq.IGlobalMock<T>
Due to browser security limitations, global mocks created by specifying class type cannot have constructor arguments.
Examples:
// global scope // Create an instance using class as ctor parameter; // Create an instance using class as ctor parameter and casting result to interface; // Create an instance using interface as type variable and class as ctor parameter; // Create an instance of 'XmlHttpRequest' global type;
Using existing objects, including function objects
method TypeMoq.GlobalMock.ofInstance targetInstance: T, globalName?: string, container?: Object, behavior?: TypeMoq.MockBehavior: TypeMoq.IGlobalMock<T>
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.
Examples:
// Create an instance using class as ctor parameter and ctor args;;; // Create an instance using a generic class as ctor parameter and ctor args;; // Create an instance from an existing object;; // Create an instance from a function object;; // Create an instance from 'window.localStorage' global object;
Dynamic global mocks
method TypeMoq.GlobalMock.ofType2 globalName: string, container?: Object, behavior?: TypeMoq.MockBehavior: TypeMoq.IGlobalMock<T>
Dynamic global mocks are created by specifying a type parameter and the name of the global object as the first constructor argument.
// Create an instance using a class as type parameter; // Create an instance using an interface as type parameter; // Create an instance of 'XmlHttpRequest' global type;
Compared to static global mocks, dynamic global mocks suffer from the same limitations as regular dynamic mocks.
Auto sandbox global mocks
method TypeMoq.GlobalScope.using ...args: TypeMoq.IGlobalMock<any>: TypeMoq.IUsingResult method TypeMoq.IUsingResult.withaction:void: void
Replacing and restoring global class types and objects is done automagically by combining global mocks with global scopes.
Examples:
// global scope // Global no args function is auto sandboxed;TypeMoq.GlobalScope.usingmock.with; // Global function with args is auto sandboxed;TypeMoq.GlobalScope.usingmock.with
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