ts-mockito
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 comparisiononce
, twice
, times
, atLeast
etc. - allows call count verification #examplecalledBefore
, 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
let mockedFoo:Foo = mock(Foo);
let foo:Foo = instance(mockedFoo);
foo.getBar(3);
foo.getBar(5);
verify(mockedFoo.getBar(3)).called();
verify(mockedFoo.getBar(5)).called();
Stubbing method calls
let mockedFoo:Foo = mock(Foo);
when(mockedFoo.getBar(3)).thenReturn('three');
let foo:Foo = instance(mockedFoo);
console.log(foo.getBar(3));
console.log(foo.getBar(999));
Stubbing getter value
let mockedFoo:Foo = mock(Foo);
when(mockedFoo.sampleGetter).thenReturn('three');
let foo:Foo = instance(mockedFoo);
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
let mockedFoo:Foo = mock(Foo);
let foo:Foo = instance(mockedFoo);
foo.getBar(1);
foo.getBar(2);
foo.getBar(2);
foo.getBar(3);
verify(mockedFoo.getBar(1)).once();
verify(mockedFoo.getBar(2)).twice();
verify(mockedFoo.getBar(between(2, 3))).thrice();
verify(mockedFoo.getBar(anyNumber()).times(4);
verify(mockedFoo.getBar(2)).atLeast(2);
verify(mockedFoo.getBar(1)).atMost(1);
verify(mockedFoo.getBar(4)).never();
Call order verification
let mockedFoo:Foo = mock(Foo);
let mockedBar:Bar = mock(Bar);
let foo:Foo = instance(mockedFoo);
let bar:Bar = instance(mockedBar);
foo.getBar(1);
bar.getFoo(2);
verify(mockedFoo.getBar(1)).calledBefore(mockedBar.getFoo(2));
verify(mockedBar.getFoo(2)).calledAfter(mockedFoo.getBar(1));
verify(mockedFoo.getBar(1)).calledBefore(mockedBar.getFoo(999999));
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);
}
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;
});
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
let mockedFoo:Foo = mock(Foo);
let foo:Foo = instance(mockedFoo);
foo.getBar(1);
foo.getBar(1);
verify(mockedFoo.getBar(1)).twice();
resetCalls(mockedFoo);
verify(mockedFoo.getBar(1)).never();
You can also reset calls of multiple mocks at once resetCalls(firstMock, secondMock, thirdMock)
Resetting mock
Or reset mock call counter with all stubs
let mockedFoo:Foo = mock(Foo);
when(mockedFoo.getBar(1)).thenReturn("one").
let foo:Foo = instance(mockedFoo);
console.log(foo.getBar(1));
console.log(foo.getBar(1));
verify(mockedFoo.getBar(1)).twice();
reset(mockedFoo);
verify(mockedFoo.getBar(1)).never();
console.log(foo.getBar(1));
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);
foo.sumTwoNumbers(1, 2);
const [firstArg, secondArg] = capture(mockedFoo.sumTwoNumbers).last();
console.log(firstArg);
console.log(secondArg);
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));
console.log(foo.getBar(1));
console.log(foo.getBar(1));
console.log(foo.getBar(1));
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));
console.log(foo.getBar(2));
console.log(foo.getBar(1));
console.log(foo.getBar(1));
console.log(foo.getBar(2));
console.log(foo.getBar(2));
Short notation:
const mockedFoo:Foo = mock(Foo);
when(mockedFoo.getBar(anyNumber())).thenReturn('one', 'two', 'three');
const foo:Foo = instance(mockedFoo);
console.log(foo.getBar(1));
console.log(foo.getBar(1));
console.log(foo.getBar(1));
console.log(foo.getBar(1));
Possible errors:
const mockedFoo:Foo = mock(Foo);
when(mockedFoo.getBar(anyNumber())).thenReturn('one');
when(mockedFoo.getBar(3)).thenReturn('one');
const foo:Foo = instance(mockedFoo);
foo.getBar(3);
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<FooInterface>();
const foo: SampleGeneric<FooInterface> = 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<SampleInterface> = mock(SampleGeneric);
const foo: SampleGeneric<SampleInterface> = 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));
console.log(foo.getBaz());
You can spy on plain objects too:
const foo = { bar: () => 42 };
const spiedFoo = spy(foo);
foo.bar();
console.log(capture(spiedFoo.bar).last());
Thanks