10.0.8 • Published 2 years ago

moq.ts v10.0.8

Weekly downloads
4,707
License
Apache-2.0
Repository
github
Last release
2 years ago

Build Status NPM version:latest NPM version:next npm downloads Dependency Status Commitizen friendly semantic-release Renovate enabled npm bundle size (minified + gzip)

License

moq.ts | Documentation

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 with 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

get.property.spec.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 mock = new Mock<ITestObject>()
    .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

set-property.spec.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(({args: [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 - instance-method.spec.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(({args: [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

A mocked object is a Proxy, that configured to track any read and write operations on properties. If you write a value to an arbitrary property the mocked object will keep it and you can read it later on. By default the prototype of mocked object is Function.

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

The default behaviour has the lowest precedence. The latest setup has the highest precedence.

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

    mock = new Mock<ITestObject>();
    mock.setup(() => It.IsAny())
      .throws(new Error("setup is missed"));

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 mocked object.

class TestObject implements ITestObject {
    
}

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

mock.object() instanceof TestObject;// true

Mimics

If you need to replicate behaviour of an existing object you can reflect mock's interactions on the object.

class Origin {
    public property = 0;

    public method(input: number): number {
        return input * this.property;
    }
}

const origin = new Origin();

const mock = new Mock<Origin>()
    .setup(() => It.IsAny())
    .mimics(origin);

const mocked = mock.object();
mocked.property = 3;
const actual = mocked.method(2);

expect(actual).toBe(6);
mock.verify(instance => instance.method(2));

typeof operator

Some operations are not possible to trap in order to keep the language consistent, one of them is typeof. The type of the proxy object will be the same as the proxy target. So at the moment the only available options is to provider target option as a create mock parameter.

class Origin {
}

const origin = new Origin();

const mock = new Mock<Origin>({target: new Origin()});

expect(typeof mock.object()).toBe(typeof new Origin());

Sponsored by 2BIT

10.1.0

2 years ago

10.0.5

2 years ago

10.0.6

2 years ago

10.0.7

2 years ago

10.0.8

2 years ago

10.0.3

2 years ago

10.0.4

2 years ago

10.0.1

3 years ago

10.0.2

3 years ago

9.0.2

3 years ago

9.0.1

3 years ago

9.0.0

3 years ago

8.0.3

3 years ago

8.0.1

4 years ago

8.0.2

4 years ago

8.0.0

4 years ago

7.4.1

4 years ago

7.4.0

4 years ago

7.3.4

4 years ago

7.3.3

4 years ago

7.3.2

4 years ago

7.3.1

4 years ago

7.3.0

4 years ago

7.2.0

4 years ago

7.1.0

4 years ago

7.0.0

5 years ago

6.5.0

5 years ago

6.4.5

5 years ago

6.4.4

5 years ago

6.4.3

5 years ago

6.4.2

5 years ago

6.4.1

5 years ago

6.4.0

5 years ago

6.3.6

5 years ago

6.3.5

5 years ago

6.3.4

5 years ago

6.3.3

5 years ago

6.3.2

5 years ago

6.3.1

5 years ago

6.3.0

5 years ago

6.2.0

5 years ago

6.1.0

5 years ago

6.0.0

5 years ago

5.0.5

5 years ago

5.0.4

5 years ago

5.0.3

5 years ago

5.0.2

5 years ago

5.0.1

6 years ago

5.0.0

6 years ago

4.0.0

6 years ago

3.0.0

6 years ago

2.8.5

6 years ago

2.8.4

6 years ago

2.8.3

6 years ago

2.8.2

6 years ago

2.8.1

6 years ago

2.8.0

6 years ago

2.7.7

6 years ago

2.7.6

6 years ago

2.7.5

6 years ago

2.7.4

6 years ago

2.7.4-rc.3

6 years ago

2.7.4-rc.2

6 years ago

2.7.4-rc.1

6 years ago

2.7.4-rc.0

6 years ago

2.7.4-1.1

7 years ago

2.7.4-1.0

7 years ago

2.7.3

7 years ago

2.7.2

7 years ago

2.7.1

7 years ago

2.7.0

7 years ago

2.6.1

7 years ago

2.6.0

7 years ago

2.5.2

8 years ago

2.5.1

8 years ago

2.5.0

8 years ago

2.4.0

8 years ago

2.3.1

8 years ago

2.3.0

8 years ago

2.2.0

8 years ago

2.1.1

8 years ago

2.1.0

8 years ago

2.0.0

8 years ago

1.0.1

8 years ago

1.0.0

9 years ago

0.0.10

9 years ago

0.0.9

9 years ago

0.0.8

9 years ago

0.0.7

9 years ago

0.0.6

9 years ago

0.0.5

9 years ago

0.0.4

9 years ago

0.0.1

9 years ago