Test Doubles
4 minute read
Test doubles are one of the main concepts we use to create fast, independent, deterministic and reliable tests. Similar to the way Hollywood uses a _stunt double* to film dangerous scenes in a movie to avoid the costly risk a high paid actor gets hurt, we use a test double in early test stages to avoid the speed and dollar cost of using the piece of software the test double is standing in for. We also use test doubles to force certain conditions or states of the application we want to test. Test doubles can be used in any stage of testing but in general, they are heavily used during the initial testing stages in our CD pipeline and used much less in the later stages. There are many different kinds of test doubles such as stubs, mocks, spies, etc.
- Test Double: A test double is a generic term for any case where you replace a production object for testing purposes.
- Dummy: A dummy is passed around but never actually used. Usually it is just used to fill parameter lists.
- Fake: A fake actually has a working implementation, but usually takes some shortcut which makes it not suitable for production (an InMemoryTestDatabase is a good example).
- Stub: A stub provides canned answers to calls made during the test, usually not responding at all to anything outside what’s programmed in for the test.
- Spy: A spy is a stub that also records some information based on how it was called. One form of this might be an email service that records how many messages it was sent.
- Mock: A mock is pre-programmed with expectations which form a specification of the calls it is expected to receive. It can throw an exception if it receives a call it doesn’t expect and is checked during verification to ensure it got all the calls it was expecting.
Resources
Examples
embed:examples/test-double-spy.java
Recommended Frameworks
Recommendations are derived from the Testing Strategy ADR.
Platform Independent Mocking Frameworks
Framework | Reasoning |
---|---|
JSON-Server |
|
Mountebank |
|
GraphQL
Framework | Reasoning |
---|---|
GraphQL-Faker |
|
GraphQL-Tools |
|
Platform Specific
Javascript
Framework | Reasoning |
---|---|
expect(jest) | For all generic assertions/mocking |
jest-dom | For DOM assertions |
supertest | For in-process test a http server |
nock | for http server endpoint assertion/mocking with NodeJS |
For FE mocking, the recommendation is kept more open to allow for other frameworks as necessary, such as msw or mirage
Android
Framework | Reasoning |
---|---|
MockK (Kotlin projects) |
|
MockWebServer |
|
iOS
For iOS, Apple test frameworks support a rich feature set, documentation and community. As a team we prefer using 1P tooling and adding Homegrown solution on top of it. The reason we do this is because Apple has been notorious in changing API’s at rapid iterations. This also results us to constantly update 3P solutions which have a risk of getting discontinued and maintaining them is a challenge. Hence iOS team prefers to use more maintainable solution which would be 1P with additional Homegrown Utilities as required.
Java (BE)
Framework | Reasoning |
---|---|
Powermock |
|
Mockito |
|