ts-mockito

by NagRock

NagRock /ts-mockito

Mocking library for TypeScript

507 Stars 57 Forks Last release: 3 months ago (v2.6.1) MIT License 268 Commits 33 Releases

Available items

No Items, yet!

The developer of this repository has not created any items for sale yet. Need a bug fixed? Help with integration? A different license? Create a request here:

ts-mockito build badge codecov

Mocking library for TypeScript inspired by http://mockito.org/

1.x to 2.x migration guide

1.x to 2.x migration guide

Main features

  • Strongly typed
  • IDE autocomplete
  • Mock creation (
    mock
    ) (also abstract classes) #example
  • Spying on real objects (
    spy
    ) #example
  • Changing mock behavior (
    when
    ) via:
  • Checking if methods were called with given arguments (
    verify
    )
    • anything
      ,
      notNull
      ,
      anyString
      ,
      anyOfClass
      etc. - for more flexible comparision
    • once
      ,
      twice
      ,
      times
      ,
      atLeast
      etc. - allows call count verification #example
    • calledBefore
      ,
      calledAfter
      - allows call order verification #example
  • Resetting mock (
    reset
    ,
    resetCalls
    ) #example, #example
  • Capturing arguments passed to method (
    capture
    ) #example
  • Recording multiple behaviors #example
  • Readable error messages (ex.
    'Expected "convertNumberToString(strictEqual(3))" to be called 2 time(s). But has been called 1 time(s).'
    )

Installation

npm install ts-mockito --save-dev

Usage

Basics

// Creating mock
let mockedFoo:Foo = mock(Foo);

// Getting instance from mock let foo:Foo = instance(mockedFoo);

// Using instance in source code foo.getBar(3); foo.getBar(5);

// Explicit, readable verification verify(mockedFoo.getBar(3)).called(); verify(mockedFoo.getBar(5)).called();

Stubbing method calls

// Creating mock
let mockedFoo:Foo = mock(Foo);

// stub method before execution when(mockedFoo.getBar(3)).thenReturn('three');

// Getting instance let foo:Foo = instance(mockedFoo);

// prints three console.log(foo.getBar(3));

// prints null, because "getBar(999)" was not stubbed console.log(foo.getBar(999));

Stubbing getter value

// Creating mock
let mockedFoo:Foo = mock(Foo);

// stub getter before execution when(mockedFoo.sampleGetter).thenReturn('three');

// Getting instance let foo:Foo = instance(mockedFoo);

// prints three console.log(foo.sampleGetter);

Stubbing property values that have no getters

Syntax is the same as with getter values.

Please note, that stubbing properties that don't have getters only works if Proxy object is available (ES6).

Call count verification

// Creating mock
let mockedFoo:Foo = mock(Foo);

// Getting instance let foo:Foo = instance(mockedFoo);

// Some calls foo.getBar(1); foo.getBar(2); foo.getBar(2); foo.getBar(3);

// Call count verification verify(mockedFoo.getBar(1)).once(); // was called with arg === 1 only once verify(mockedFoo.getBar(2)).twice(); // was called with arg === 2 exactly two times verify(mockedFoo.getBar(between(2, 3))).thrice(); // was called with arg between 2-3 exactly three times verify(mockedFoo.getBar(anyNumber()).times(4); // was called with any number arg exactly four times verify(mockedFoo.getBar(2)).atLeast(2); // was called with arg === 2 min two times verify(mockedFoo.getBar(1)).atMost(1); // was called with arg === 1 max one time verify(mockedFoo.getBar(4)).never(); // was never called with arg === 4

Call order verification

// Creating mock
let mockedFoo:Foo = mock(Foo);
let mockedBar:Bar = mock(Bar);

// Getting instance let foo:Foo = instance(mockedFoo); let bar:Bar = instance(mockedBar);

// Some calls foo.getBar(1); bar.getFoo(2);

// Call order verification verify(mockedFoo.getBar(1)).calledBefore(mockedBar.getFoo(2)); // foo.getBar(1) has been called before bar.getFoo(2) verify(mockedBar.getFoo(2)).calledAfter(mockedFoo.getBar(1)); // bar.getFoo(2) has been called before foo.getBar(1) verify(mockedFoo.getBar(1)).calledBefore(mockedBar.getFoo(999999)); // throws error (mockedBar.getFoo(999999) has never been called)

Throwing errors

let mockedFoo:Foo = mock(Foo);

when(mockedFoo.getBar(10)).thenThrow(new Error('fatal error'));

let foo:Foo = instance(mockedFoo); try { foo.getBar(10); } catch (error:Error) { console.log(error.message); // 'fatal error' }

Custom function

You can also stub method with your own implementation

let mockedFoo:Foo = mock(Foo);
let foo:Foo = instance(mockedFoo);

when(mockedFoo.sumTwoNumbers(anyNumber(), anyNumber())).thenCall((arg1:number, arg2:number) => { return arg1 * arg2; });

// prints '50' because we've changed sum method implementation to multiply! console.log(foo.sumTwoNumbers(5, 10));

Resolving / rejecting promises

You can also stub method to resolve / reject promise

let mockedFoo:Foo = mock(Foo);

when(mockedFoo.fetchData("a")).thenResolve({id: "a", value: "Hello world"}); when(mockedFoo.fetchData("b")).thenReject(new Error("b does not exist"));

Resetting mock calls

You can reset just mock call counter

// Creating mock
let mockedFoo:Foo = mock(Foo);

// Getting instance let foo:Foo = instance(mockedFoo);

// Some calls foo.getBar(1); foo.getBar(1); verify(mockedFoo.getBar(1)).twice(); // getBar with arg "1" has been called twice

// Reset mock resetCalls(mockedFoo);

// Call count verification verify(mockedFoo.getBar(1)).never(); // has never been called after reset

You can also reset calls of multiple mocks at once

resetCalls(firstMock, secondMock, thirdMock)

Resetting mock

Or reset mock call counter with all stubs

// Creating mock
let mockedFoo:Foo = mock(Foo);
when(mockedFoo.getBar(1)).thenReturn("one").

// Getting instance let foo:Foo = instance(mockedFoo);

// Some calls console.log(foo.getBar(1)); // "one" - as defined in stub console.log(foo.getBar(1)); // "one" - as defined in stub verify(mockedFoo.getBar(1)).twice(); // getBar with arg "1" has been called twice

// Reset mock reset(mockedFoo);

// Call count verification verify(mockedFoo.getBar(1)).never(); // has never been called after reset console.log(foo.getBar(1)); // null - previously added stub has been removed

You can also reset multiple mocks at once

reset(firstMock, secondMock, thirdMock)

Capturing method arguments

let mockedFoo:Foo = mock(Foo);
let foo:Foo = instance(mockedFoo);

// Call method foo.sumTwoNumbers(1, 2);

// Check first arg captor values const [firstArg, secondArg] = capture(mockedFoo.sumTwoNumbers).last(); console.log(firstArg); // prints 1 console.log(secondArg); // prints 2

You can also get other calls using

first()
,
second()
,
byCallIndex(3)
and more...

Recording multiple behaviors

You can set multiple returning values for same matching values

const mockedFoo:Foo = mock(Foo);

when(mockedFoo.getBar(anyNumber())).thenReturn('one').thenReturn('two').thenReturn('three');

const foo:Foo = instance(mockedFoo);

console.log(foo.getBar(1)); // one console.log(foo.getBar(1)); // two console.log(foo.getBar(1)); // three console.log(foo.getBar(1)); // three - last defined behavior will be repeated infinitely

Another example with specific values

let mockedFoo:Foo = mock(Foo);

when(mockedFoo.getBar(1)).thenReturn('one').thenReturn('another one'); when(mockedFoo.getBar(2)).thenReturn('two');

let foo:Foo = instance(mockedFoo);

console.log(foo.getBar(1)); // one console.log(foo.getBar(2)); // two console.log(foo.getBar(1)); // another one console.log(foo.getBar(1)); // another one - this is last defined behavior for arg '1' so it will be repeated console.log(foo.getBar(2)); // two console.log(foo.getBar(2)); // two - this is last defined behavior for arg '2' so it will be repeated

Short notation:

const mockedFoo:Foo = mock(Foo);

// You can specify return values as multiple thenReturn args when(mockedFoo.getBar(anyNumber())).thenReturn('one', 'two', 'three');

const foo:Foo = instance(mockedFoo);

console.log(foo.getBar(1)); // one console.log(foo.getBar(1)); // two console.log(foo.getBar(1)); // three console.log(foo.getBar(1)); // three - last defined behavior will be repeated infinity

Possible errors:

const mockedFoo:Foo = mock(Foo);

// When multiple matchers, matches same result: when(mockedFoo.getBar(anyNumber())).thenReturn('one'); when(mockedFoo.getBar(3)).thenReturn('one');

const foo:Foo = instance(mockedFoo); foo.getBar(3); // MultipleMatchersMatchSameStubError will be thrown, two matchers match same method call

Mocking interfaces

You can mock interfaces too, just instead of passing type to

mock
function, set
mock
function generic type Mocking interfaces requires
Proxy
implementation
let mockedFoo:Foo = mock(); // instead of mock(FooInterface)
const foo: SampleGeneric = instance(mockedFoo);

Mocking types

You can mock abstract classes

const mockedFoo: SampleAbstractClass = mock(SampleAbstractClass);
const foo: SampleAbstractClass = instance(mockedFoo);

You can also mock generic classes, but note that generic type is just needed by mock type definition

const mockedFoo: SampleGeneric = mock(SampleGeneric);
const foo: SampleGeneric = instance(mockedFoo);

Spying on real objects

You can partially mock an existing instance:

const foo: Foo = new Foo();
const spiedFoo = spy(foo);

when(spiedFoo.getBar(3)).thenReturn('one');

console.log(foo.getBar(3)); // 'one' console.log(foo.getBaz()); // call to a real method

You can spy on plain objects too:

const foo = { bar: () => 42 };
const spiedFoo = spy(foo);

foo.bar();

console.log(capture(spiedFoo.bar).last()); // [42]

Thanks

  • Szczepan Faber (https://www.linkedin.com/in/szczepiq)
  • Sebastian Konkol (https://www.linkedin.com/in/sebastiankonkol)
  • Clickmeeting (http://clickmeeting.com)
  • Michał Stocki (https://github.com/michalstocki)
  • Łukasz Bendykowski (https://github.com/viman)
  • Andrey Ermakov (https://github.com/dreef3)
  • Markus Ende (https://github.com/Markus-Ende)
  • Thomas Hilzendegen (https://github.com/thomashilzendegen)
  • Johan Blumenberg (https://github.com/johanblumenberg)

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.