_Test double_ is the generic term for any case where you replace a production object for testing purposes. [^mf1]
[^mf1]: [TestDouble](https://www.martinfowler.com/bliki/TestDouble.html) by [[@Martin Fowler]]
## Kinds of test doubles [^mf1]
- **Dummy** objects are passed around but never actually used. Usually they are just used to fill parameter lists.
- **Fake** objects actually have working implementations, but usually take some shortcut which makes them not suitable for production (an InMemoryTestDatabase is a good example).
- **Stubs** provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test.
- **Spies** are stubs that also record some information based on how they were called. One form of this might be an email service that records how many messages it was sent.
- **Mocks** are pre-programmed with expectations which form a specification of the calls they are expected to receive. They can throw an exception if they receive a call they don't expect and are checked during verification to ensure they got all the calls they were expecting.
## Benefits of test doubles
- They eliminate the overhead of having to provision and configure a remote service in order to test a particular behaviour
- [[Test doubles enable the testing of non-deterministic behaviours of remote services]]
- They can speed up test execution time by removing latency caused by disk or network I/O
- They can remove the need to seed test data into a system in the "Arrange" phase of a test run
## Challenges and limitations of using test doubles
- [[Test doubles can mask incorrect assumptions]] and so may not be appropriate for use in [[Integration testing]]
- Test doubles add some complexity overhead to your test setup and require you to write your modules in such a way that these doubles can easily be "injected" to your module under test.
- In order to know how to implement your test double (e.g. set expectations for a mock, structure of a canned response from a fake), you often need to first invoke the real service itself and inspect its response to a given input, in particular when talking to services that don't have comprehensive docs. To do this, you need to provision the real service and configure your test code to connect and authenticate with it (or configure a tool such as Postman to do this). This removes the potential benefit of tests which use test doubles being faster to author.
- If the service that needs substituted by a test double is not part of your own code but rather an indirect dependency of a third-party package your code is using, it can be particularly difficult or impossible to inject your double without swapping out your direct third party dependency entirely.
- Consider the case in an integration or end-to-end test case where the code-under-test is running in a deployed environment and the response to a non-deterministic behaviour needs to be verified (e.g. an overloading of a downstream service). It can be particularly challenging to instruct the code to conditionally inject a test double in this instance.