Best Practices: API Mocking
Pro Tip: Mocking is great when you only have a few API interactions to mock. For a more scalable approach, try API virtualization.
Introduction
The possibility to create mock-ups / mock system components is becoming increasingly important in contemporary development. It enables a number of development and testing workflows that greatly enhance the agility of developments teams in enterprises with complex infrastructures and systems. Just like testing, mocking can be done at many levels; code, API, service and infrastructure to name some, and can be used for both functional and non-functional scenarios. Specifically, API mocking can empower your development and testing teams in their everyday work.
What is API Mocking?
The most common term for creating simulated components is mocking, but others are also used, and partly apply to different things; stubbing, simulation, and virtualization. The basic concept is the same - instead of using an actual software component (an API in our case) – a “replacement” version of that API is created and used instead. It behaves as the original API, but lacks many of the functional and non-functional characteristics of the original component. Which term is applicable depends on the degree to which the mock-up corresponds to the actual API:
- Stubbing: mostly a placeholder without real functionality
- Mocking: basic functionality required for a specific testing or development purpose
- Simulation: complete functionality for testing or development purposes
- Virtualization: imulation that is deployed into an operational, manageable and controllable environment
Since APIs are commonly used to integrate a component with its surroundings, API mocking has a number of extremely useful applications. To demonstrate this, we will use an example with a component that uses a number of APIs to talk to a number of auxiliary systems and services (Legacy, Mobile Apps, Infrastructure, Databases, Peer Services, 3rd Party Components).
Common API Mocking Scenarios
Mocking During Development
Developers are frequently tasked with writing code that integrates with other system components via APIs. Unfortunately, it might not always be desirable or even possible to actually access those systems during development. There could be security, performance or maintenance issues that make them unavailable – or they might simply not have been developed yet.
This is where mocking comes in: instead of developing code with actual external dependencies in place, a mock of those dependencies is created and used instead. Depending on your development needs this mock is made “intelligent” enough to allow you to make the calls you need and get similar results back as you would from the actual component, thus enabling development to move forward without being hindered by eventual unavailability of external systems you depend on.
Mocking For Functional Tests
The testing usage of mocking is similar to development. Components may be unavailable for security, performance, maintenance or non-existence reasons. A basic mock of the component to be tested can be more than enough to get testing efforts started. Things like discovering operations that need to be tested, creating initial test scripts, scheduling test execution and so on, can be done even with a fairly basic mock.
There is a limit here; a mock will not be a full simulation of the corresponding component – which will put a limit to what kind of functional tests that can be used with it – but it can definitely be enough to get the testing effort started.
Mocking For External Components
When doing functional testing of a component which depends on external components accessed via APIs is a situation where mocking can be very useful.
For example you might need to test a geo-location functionality in your component that in turn uses Google Maps APIs for coordinate lookups. Instead of using the actual Google Maps API you could use a corresponding mock that would return known results to your component. This helps you validate that the results from your component are returned correctly, as they are not affected by eventual inconsistencies in the external components. An added benefit is that you keep your usage quota of external APIs to a minimum.
Mocking For Non-Functional Testing
Non-functional testing aims at making sure that your component or system under test behaves correctly in regards to performance, SLAs, security, auditing , traceability, et c. The desired behavior of your component can indirectly depend on responses from external dependencies.
For example, you might want to make sure that if you get an error from your back-end legacy system that it will be logged correctly, or that your component gracefully handles situations like when a 3rd party API stops responding during a load test.
When doing non-functional testing, the mock is configured to behave in specific ways, dictated by the needs of the test goals. Some of the benefits with using mocking for non-functional testing.
- Mocks can respond faster - Saving time during testing due to lower overhead, also provides more load on the component due to less idle time.
- Mocking 3rd party components - Saving on costs for using external APIs in load tests, or replacing unavailble external dependencies.
- Simulating various response times - Simulating a greater range of possible response times and outages is a good way to see how your component handles them.
Mocking For Integration and Demonstration Purposes
Sometimes an API needs to be made available to consumers before they can try them out before committing to use them. In this case, a complete simulation of the API can be provided, online or as a distributable for local deployment. The consumer can try out API from their system, and make basic requirement assessment without imposing any cost on the actual API.
The same simulation can naturally be used in pre-sales demos as well - ensuring that a “working” version of the API is always available.
Mocking Best Practices
When creating and using mocks as in the practices described above, here a couple of things to consider:
- Make the mock 100% technically equivalent - A mock should support the same transport protocols, schemas, et c as the actual API, and be. The mock API should be accessible exactly like the original service and not require any special tooling or libraries.
- Use recording tools or log files to create complex mock behavior - For cases when you are uncertain about messages to return, record them with a proxy or packet-sniffer and then use those recordings to create the mock behavior.
- Use mocks to create negative tests - Simulate unexpected errors, long response times or even invalid messages to make sure your API client handles those gracefully.
- Use mocks to enable continuous testing - of yourcomponents; by mocking out external dependencies and APIs you can run your tests as often as you want without affecting those dependencies and without being affected by any unexpected changes or irregularities within them.
- Create your mock so that it can forward requests - If you are using mocking for enabling development, being able to to the actual API as it becomes available for certain operations allows you to partially replace mocked operations / behavior with its real counterpart as required by your scenario.
Putting It All Together
API mocking is a powerful concept that can be put to use in several development and testing scenarios.
- External dependecies - Testing unexpected behavior and 3rd party dependencies.
- Isolated development - Development environment for use by operation and architects.
- Early functional testing - Starting testing work early in development, even before actual components are available.
- Customer evaluation - Providing evaluation and pre-sales opportunities.
- Avoiding API dependencies - Developing against future or unavailable functionality.