Creating a mock of a class

ts-mockito

With ts-mockito you first create a mock “class” or “constructor”, and you can then create a real non-fake instance from this mock.

typemoq

The same goes for typemoq .

substitute.js

For substitute.js , the instance and the fake is one and the same.

Creating a mock of an interface

Creating a mock from an interface makes TDD a lot easier with a lot less code, all while being able to compile along the way. With interface mocking, you can:

Start by defining your interfaces (no implementation). Depend on those interfaces in your code. Write the tests for the interfaces using fakes (you can fake the interfaces without writing the classes first!). Implement the code with real classes. Smile. You were able to have full strong-typing and something that actually compiles all the way through the process. No squiggly lines, just pure pleasant TDD.

ts-mockito

This is unfortunately not supported.

typemoq

The same goes for typemoq — not supported.

substitute.js

In substitute.js , you can fake from an interface just fine. The magic behind this is possible due to ES6 proxies.

Stubbing methods

In this example we’ll compare how the three frameworks handle stubbing of methods.

ts-mockito

With ts-mockito you specify the arguments and return values on the mock object within wrapper functions.

typemoq

The same goes for typemoq .

substitute.js

For substitute.js , you can define your return values on the mock itself and yet use it in a fluent and strong typed manner.

Stubbing properties

In this example we’ll compare how the three frameworks handle stubbing of properties.

ts-mockito

With ts-mockito you specify the return values on the mock object within wrapper functions.

typemoq

The same goes for typemoq .

substitute.js

For substitute.js , you can define your return values on the mock itself and yet use it in a fluent and strong typed manner.

Throwing errors

In this example we’ll compare how the three frameworks handle throwing errors. The same syntax across all frameworks also apply for methods in a similar manner described above, so we won’t go through that.

ts-mockito

With ts-mockito you specify the exception to throw on the mock object within wrapper functions.

typemoq

The same goes for typemoq .

substitute.js

For substitute.js , you use the returns function and wrap it in a lambda to throw an error.

Call count verification

In this example we’ll compare how the three frameworks handle call count verification. The same syntax across all frameworks also apply for properties, so we won’t go through that.

Note that substitute.js does not support the “at least n times” verification nor the “fewer than n times” verification because I personally believe it is bad practise — your tests should always be deterministic. You should always know the amount of calls to expect in a test.

ts-mockito

With ts-mockito you specify the operation to match on the mock object within wrapper functions.

typemoq

The same goes for typemoq .

substitute.js

For substitute.js , you use the received function and call the operation on its return value.

Alternatively, you can also use didNotReceive which does exactly what you would expect.

Proxying calls

Proxying calls can be useful if you want your fake method to do something else.

ts-mockito

With ts-mockito you specify the operation to match on the mock object within wrapper functions, and then use another function to specify which method to proxy calls to.

typemoq

The same goes for typemoq .

substitute.js

For substitute.js , you use the mimicks function and specify which function to proxy calls to.

Matching arguments

Argument matchers allow you to be more explicit about when you want to fake something, or what calls you expect to receive.

ts-mockito

With ts-mockito you use functions like anything and between to match arguments.

I have not found a way to specify a custom lambda to express a custom matcher yet in ts-mockito — let me know if you know of any in the comments section.

typemoq

Almost the same as ts-mockito , but supports lambdas.

substitute.js

Here, the syntax is nice and clear. A nice little detail is that there is strong-typing all the way even as you type, with full type inference (it even knows what type x is in the Arg.is function.

Errors produced by call verification

Proxying calls can be useful if you want your fake method to do something else.

ts-mockito

ts-mockito displays the method name and parameters as well as how many times a call was expected, but does not show the total calls that were recorded.

The above code throws:

Expected “add(strictEqual(1), strictEqual(2))” to be called at least 1 time(s). But has been called 0 time(s).

typemoq

The same goes for typemoq , except it also displays a list of calls recorded

The above code throws:

Expected invocation of RealCalculator.add(It.isValue(1),It.isValue(2)) at least 1 times, invoked 0 times Configured setups:

RealCalculator.add(It.isValue(1),It.isValue(2)) Performed invocations:

RealCalculator.add(3,4)

substitute.js

For substitute.js , you use the mimicks function and specify which function to proxy calls to.

The above code will throw:

Expected one or more calls to the method c with arguments [1, 2], but received none of such calls.

All calls received to method c:

-> 1 call with arguments [3, 4]

Limitations

The above all looks quite good, right? But there are limitations in substitute.js like any other framework.

Below is a list all of the things the other frameworks can do that substitute.js can’t, and a reason for not supporting it.

Partial mocks

Partial mocks are typically bad if you rely on only a few faked methods. Typically when testing, you want to fake either everything or almost everything.

While substitute.js does not support partial mocks, you can explicitly proxy each method you want to “mimick” from the real instance.

Call order verification

The outside world (using the public interface of your unit) should not care about which order your unit calls its dependencies’ methods. I see this as an anti-pattern, which is why it is not supported.

More?

Are there more examples that substitute.js can’t do that the others can? Let me know in the comments, and I’ll add it or justify why it hasn’t been added to the framework.