What is ts-mockito?
ts-mockito is a mocking library for TypeScript that allows developers to create mock objects and verify interactions with them. It is inspired by the Java library Mockito and provides a fluent API for creating and using mocks in unit tests.
What are ts-mockito's main functionalities?
Creating Mocks
This feature allows you to create a mock object of a class. The mock object can then be used to stub methods and verify interactions.
const myMock = mock(MyClass);
Stubbing Methods
This feature allows you to define the behavior of a mock object's method. In this example, when `someMethod` is called on `myMock`, it will return 'someValue'.
when(myMock.someMethod()).thenReturn('someValue');
Verifying Interactions
This feature allows you to verify that a method on a mock object was called a specific number of times. In this example, it verifies that `someMethod` was called exactly once.
verify(myMock.someMethod()).once();
Capturing Arguments
This feature allows you to capture the arguments passed to a mock object's method. In this example, it captures the arguments of the last call to `someMethod`.
const [arg1, arg2] = capture(myMock.someMethod).last();
Other packages similar to ts-mockito
jest
Jest is a popular testing framework for JavaScript and TypeScript that includes built-in mocking capabilities. Unlike ts-mockito, Jest provides an all-in-one solution for testing, including test runners, assertion libraries, and mocking functionalities.
sinon
Sinon is a standalone test spies, stubs, and mocks library for JavaScript. It provides similar functionalities to ts-mockito but is more focused on JavaScript and does not provide the same TypeScript-specific features.
typemoq
typemoq is another mocking library for TypeScript. It provides a similar API to ts-mockito but has different syntax and features. It is also inspired by the .NET Moq library.
ts-mockito
Mocking library for TypeScript inspired by http://mockito.org/
Main features
- Strongly typed
- IDE autocomplete
- Mock creation (
mock
) - Changing mock behavior (
when
) via:
thenReturn
- return valuethrowError
- throw an errorthenCall
- call custom method
- Checking if methods were called with given arguments (
verify
)
anything
, notNull
, anyString
etc. - for more flexible comparisiononce
, twice
, times
, atLeast
etc. - allows call count verificationcalledBefore
, calledAfter
- allows call order verification
- Resetting mock (
reset
, resetCalls
) - Capturing arguments passed to method (
thenCapture
) - Recording multiple behaviors
- 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(fooMock.getBar(3)).called();
verify(fooMock.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
// 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);
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)).atMoast(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)).throwError(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));
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();
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));
Capturing method arguments
let mockedFoo:Foo = mock(Foo);
let foo:Foo = instance(mockedFoo);
let firstArgCaptor: Captor<number> = new Captor<number>();
let secondArgCaptor: Captor<number> = new Captor<number>();
when(mockedFoo.sumTwoNumbers(anything(), anything())).thenCapture(firstArgCaptor, secondArgCaptor);
foo.sumTwoNumbers(1, 2);
foo.sumTwoNumbers(3, 4);
console.log(firstArgCaptor.getFirstCallValue());
console.log(firstArgCaptor.getLastCallValue());
console.log(secondArgCaptor.getFirstCallValue());
console.log(secondArgCaptor.getLastCallValue());
You can also capture single arg and give matcher to the other
let mockedFoo:Foo = mock(Foo);
let foo:Foo = instance(mockedFoo);
let secondArgCaptor: Captor<number> = new Captor<number>();
when(mockedFoo.sumTwoNumbers(3, anything())).thenCapture(new Captor(), secondArgCaptor);
foo.sumTwoNumbers(1, 2);
foo.sumTwoNumbers(3, 4);
console.log(secondArgCaptor.getFirstCallValue());
console.log(secondArgCaptor.getLastCallValue());
Recording multiple behaviors
If more than one behavior is set, first matching is executed and removed
let mockedFoo:Foo = mock(Foo);
when(mockedFoo.getBar(anyNumber())).thenReturn('one');
when(mockedFoo.getBar(anyNumber()).thenReturn('two');
when(mockedFoo.getBar(anyNumber())).thenReturn('three');
let 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');
when(mockedFoo.getBar(1)).thenReturn('second time one');
when(mockedFoo.getBar(2)).thenReturn('two');
let foo:Foo = instance(mockedFoo);
console.log(foo.getBar(1));
console.log(foo.getBar(1));
console.log(foo.getBar(1));
console.log(foo.getBar(2));
console.log(foo.getBar(2));
Thanks