Skip to content

rnrn/moq.ts

 
 

Repository files navigation

Build Status NPM version npm downloads Dependency Status License

moq.ts

Moq for Typescript. Inspired by c# Moq library.

Important

This implementation depends on Proxy object. So if your production code is not compatible with this I would recommend you separate you production code and testing code into dedicated projects. If you need help whit this then ask me.

Install

npm install moq.ts --save-dev

Quick start

moq.ts as the original Moq library is intended to be simple to use, strongly typed (no magic strings!, and therefore full compiler-verified and refactoring-friendly) and minimalistic (while still fully functional!).

You can find a pretty full set of usages in the integration tests. Check out tests.integration folder.

Mocking property of objects

mock-get.property.IntegrationTests.ts

import {Mock, It, Times, ExpectedGetPropertyExpression} from 'moq.ts';
interface ITestObject {
    property1: number;
    property2: number;
    property3: number;
    property4: number;
    method(): void;
}

const property4Name = 'property4';
const mockName = 'mock name is optional';
const mock = new Mock<ITestObject>(mockName)
    .setup(instance => instance.property1)
    .returns(1)
    
    .setup(instance => It.Is((expression: ExpectedGetPropertyExpression) => expression.name === 'property2'))
    .returns(100)
    
    //let's deny any write operation on the property for all values
    .setup(instance => {instance.property2 = It.Is(() => true)})
    .returns(false)
    
    .setup(instance => instance.property3)
    .callback(()=> 10 + 10)
    
    .setup(instance => instance[property4Name])
    .throws(new Error('property4 access'))
    
    //since a method is a property that holds a pointer to a function
    .setup(instance => instance.method)
    .returns(()=>{console.log('The method was called')});

const object = mock.object();
object.method();

mock.verify(instance=> instance.property1, Times.Never());

Mocking property setting

The documentation on returned value from 'set hook' on Proxy object

mock-set.property.IntegrationTests.ts

import {Mock, It, Times, ExpectedSetPropertyExpression} from 'moq.ts';
interface ITestObject {
    property: number|any;
}

const value = {field: new Date()};

const mock = new Mock<ITestObject>()
    .setup(instance => {instance.property = 1})
    //true - allows the write operation
    .returns(true)
    
    .setup(instance => It.Is((expression: ExpectedSetPropertyExpression) => expression.name === 'property' && expression.value === 2))
    //false - denies the write operation
    .returns(false)
    
    .setup(instance => {instance.property = It.Is(value => value === 3)})
    // allows the write operation
    .callback(()=> true)
    
    .setup(instance => {instance.property = value})
    .throws(new Error('an object has been written into property'));


const object = mock.object();
object.property = 1;

mock.verify(instance=> {instance.property = 1}, Times.Once());

Mocking functions

mock-method.property.IntegrationTests.ts

import {Mock, It, Times} from 'moq.ts';
interface ITestFunction {
    (arg: number|any): string;
}

const value = {field: new Date()};

const mock = new Mock<ITestFunction>()
    .setup(instance => instance(1))
    .returns('called with 1')
    
    .setup(instance => instance(2))
    .callback((argument)=> argument === 2 ? 'called with 2' : `called with ${argument}`)
    
    .setup(instance => instance(value))
    .throws(new Error('Argument is object with date'))
    
    .setup(instance => instance(It.Is(value => value === 4)))
    .returns('called with 4');

const method = mock.object();
const actual = method(1);

mock.verify(instance => instance(1), Times.Once());
mock.verify(instance => instance(It.Is(value=> value === 1)), Times.Exactly(1));

Mocking functions of objects

mock-named.method.IntegrationTests.ts

import {Mock, It, Times} from 'moq.ts';
interface ITestObject {
   method(arg1: number, arg2: string): Date;
}

const values = ['a', 'b', 'c'];

const mock = new Mock<ITestObject>()
   .setup(instance => instance.method(1, values[0]))
   .returns(new Date(2016))
   
   .setup(instance => instance.method(It.Is(value => value === 2), values[1]))
   .callback((arg1, arg2)=> new Date(2017 + arg1))
   
   .setup(instance => instance.method(3, It.Is(value => value === values[2])))
   .throws(new Error('Invoking method with 3 and c'));

const object = mock.object();
const actual = object.method(1, 'a');

mock.verify(instance => instance.method(2, 'a'), Times.Never());

Mock behavior

You can control mock behavior when accessing to a property without a corresponding setup.

    mock = new Mock<ITestObject>()
    .setBehaviorStrategy(MockBehavior.Loose)
    //or
    .setBehaviorStrategy(MockBehavior.Strict);

The default behavior is strict.

MockBehavior.Strict

Accessing to an unset property will return undefined value; Accessing to an unset method of an object will throw TypeError exception; It does not matter if a method is a part of mocked type. If you want to track a method you can define a default setup:

const mock = new Mock<ITestObject>()
    .setup(instance => instance.method(It.Is(()=>true), It.Is(()=>true)))
    .returns(undefined);
MockBehavior.Loose

Accessing to an unset property or a method will return a pointer to a spy function; You can call this function and it will be tracked.

Mock prototype

If you need to make work instanceof operator or you need to deal with prototype of the mock object you can use prototypeof function of Mock class. Or you can use Object.getPrototypeOf or Object.setPrototypeOf functions on mock object.

class TestObject implements ITestObject {
    
}

const mock = new Mock<ITestObject>()
                .prototypeof(TestObject)
                .object();

mock.object() instanceof TestObject;// true
P.S.

I am a team leader of a team of software developers. We are available for contract work. Ready to work with the best practices (TDD, eXtream programming, agile). From your side you need to provide an agile product manager. Angular2, Angular1, Nativescript, ASP.NET webAPI, WPF. Love testing. Just drop me a note at dvabuzyarov(at)gmail.com

Sponsored by 2BIT

About

Moq for Typescript

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • TypeScript 96.6%
  • JavaScript 3.4%