When it comes to mocking in TypeScript…

Michał Stocki
4 min readMar 25, 2017

One may ask: do we really need a special tool for creating mock objects in TypeScript, while there are several robust libraries written in JavaScript? We can use Mocha or Jasmine as a test framework, we can also use Karma and Chai—they’re all JavaScript libraries and work successfully, so why can’t we use Sinon.JS for mocking?

It’s all about types

Developing a quite large application (over 500 classes and around 2000 tests) written from scratch in TypeScript gave me a chance to experience a full range of problems coming from usage of a not-fully-typed mocking framework. The most painful issues are connected with automatic refactoring. When the objects used in tests are not typed (and the IDE is not able to strictly determine the types), the IDE won’t be able to figure out which usages of them should be modified, when we rename a method in one of them. In the other words: let’s say, we have over ten classes containing a method called load(). When we try to rename one of them, IDE will change all mocking configuration connected with the remaining nine occurrences of the load(), kindly breaking tens of tests.

WebStorm IDE listing over 10 possible declarations of the load() method stubbed with Sinon.JS.

Repeating problems with the mocking framework forced our team to search better, TypeScript-friendly tools. When we were starting our adventure with TypeScript in 2015, there were no mocking frameworks dedicated to this brilliant language. Moreover, the language was just after 1.5 release which brought revolutionary changes, and IDE didn’t even support suggestions of ES6 imports — we were forced to write them manually. Thankfully, the situation changed significantly and now, we can choose one of the several alternatives written with TypeScript in mind. Let’s compare two of them.

typemoq vs. ts-mockito

typemoq seems to be one of the most popular mocking libraries created for TypeScript. Its syntax is highly inspired by moq .NET library.

ts-mockito has an amazing syntax inspired by Java Mockito, one of the most popular Java mocking frameworks.

Mock creation

Let’s say we have a class TestedClass which has a dependency Bar, which we would like to mock in our tests.

class Bar {  constructor() {
console.info('constructor called!');
}
public getValueBy(count:number):string {
}
public saveState(state:SomeSate):void {
}
}

In order to create a mock object for the class in typemoq, we use a following syntax:

// typemoq
const bar:TypeMoq.IMock<Bar> = TypeMoq.Mock.ofType(Bar);
// prints 'constructor called!'
const tested:TestedClass = new TestedClass(bar.object);

It’s worth noting, that when we create a mock, typemoq is executing a constructor of the mocked class, which may be highly undesired in some cases.

In ts-mockito, we’ll type:

// ts-mockito
const bar:Bar = mock(Bar);
const tested:TestedClass = new TestedClass(instance(bar));

Mock setup

In order to let mocked class return a particular value for a given parameters we will use the following syntax in typemoq:

// typemoq
bar
.setup(bar => bar.getValueBy(TypeMoq.It.isValue(12)))
.returns(() => 'twelve');

The same behaviour we can accomplish in ts-mockito using the following syntax:

// ts-mockito
when(bar.getValueBy(12)).thenReturn('twelve');

Calls verification

Often we need to check whether some method was called with a data structure which is deep equal, the one we created in test:

// typemoq
bar.verify(
(bar) => bar.saveState(TypeMoq.It.isValue(state)),
TypeMoq.Times.once()
);
// ts-mockito
verify(bar.saveState(deepEqual(state))).once();

Type checking and suggestions

Both libraries are designed to be type-safe and to allow best possible IDE type suggestions.

compiler argument type checking in typemoq

IDE auto-complete is one of the major advantages of development in statically-typed language. When we choose such language, we would like to get as much profit from this feature as possible. Tests shouldn’t be an exception.

IDE auto-complete with ts-mockito

Advanced features

Both libraries are able to:

  • set up complex mock behaviours with custom functions,
  • define general type of expected method argument (any number, any string, anything),
  • record method calls (getting arguments passed to an invoked method),
  • verify call count with a given arguments,
  • verify method call order,
  • mock getters,
  • setup different behaviours for subsequent method calls,
  • run in both browser and node.js,
  • run with compilation targeting both ES5 and ES6.

Features available only in typemoq:

  • mocking interfaces (requires support for ES6 Proxy),
  • partial mocking,
  • creating global mocks and sandboxing them,
  • mocking existing objects (instances),
  • mocking standalone functions (ts-mockito allows to mock only classes),
  • verifying setter invocations,
  • specifying mock setup as an expectation (verifying all at once).

Conclusion

Both libraries are worth our attention. typemoq have an impressive number of advanced features which make this library a tool for really sophisticated mocking. ts-mockito attracts with an amazing syntax which let us forget about looking into the library’s documentation. The syntax of ts-mockito is also more meaningful. It matters, especially when we write our tests with a conviction of making them a living documentation of our code. It can’t be denied that typemoq has twice as many advanced features as his rival. Nevertheless, my experience shows clear that simpler usage gives much more profit in everyday use — magic mocking is needed rarely and rather should be avoided. That’s why I’ve chosen ts-mockito.

Bonus

I created two repositories demonstrating configuration and simple usage of both libraries. Projects are available on github:

https://github.com/michalstocki/typemoq-example
https://github.com/michalstocki/ts-mockito-example

--

--