A mock server can prove useful in many circumstances. Imagine you’re an engineer working on optimizing a feature inside of an existing API that relies on multiple other microservices to function properly. To fully test the optimizations, you’ll have to set up test versions of all the dependencies, which quickly proves to be quite a task in and of itself.
This is where a mocks—a server that simulates the behavior of a real server—can be very beneficial. It allows developers to test the behavior of their applications without relying on the real dependency, whether it be an internal or third-party API.
In the example above, the mock can be configured to simulate the response of each dependency. This not only saves you as a developer the trouble of setting up multiple extra dependencies as part of your testing, but also ensures consistency between each test.
Mock servers return static responses and require (almost) no logic to be run. In turn, some dependencies may include large amounts of logic, which by themselves can start to fail, ultimately impacting your testing.
In this post, you’ll get a high-level understanding of what it takes to set up a mock server, what a good one looks like, and how user traffic plays a role. If you’re interested in seeing the specific implementation steps needed to set up a mock server, you might be interested in reading “How to Mock APIs in Kubernetes.”
What Is a Mock Server?
As stated in the introduction, a mock server is a fake API with the sole purpose of simulating the behavior of an application’s dependencies. This is usually achieved in one of two ways:
- Manually configuring each response, based on what’s expected from the dependency
- Generating a mock server from something like an API schema
Some mock servers are fairly simple and will just return a given response on a given request URL, whereas some are more advanced, using matching algorithms to ensure the most appropriate response. For example, looking at a combination of headers, path, query, and request body. Or returning the same response for /blog?page=1
and /blog?page=2
, if the distinction of different blog posts isn’t important.
As for the use of mock servers, there are quite a few places where they prove useful, with a few examples being:
- When testing APIs
As detailed in the introduction, mock servers can be very helpful when developing or optimizing APIs.
- In microservice architectures
Whenever you’re working with an architecture of many services, the task of setting up all dependencies can quickly become complex, in which case the ability to set up a single mock server can save a lot of time and headache
In a CI/CD pipeline—especially in the CI step—you’ll often want to test an application in isolation, which can be made much more efficient by using mock servers. In some cases, like load testing, mocks will likely even be a necessity
It’s not only when load testing is performed as part of a CI/CD pipeline that mocks are useful. Mock servers are generally useful when performing nonfunctional tests—like chaos testing, where you mix in latency and errors to see how the app exercises its error handling branches of the code—as they eliminate any performance impact from dependencies, as well as removing the need for production-scale resources when simulating a large amount of transactions per second, as it’s able to match requests and respond with a fraction of the actual logic.
Likely an unexpected use case for many, this is nonetheless a powerful one. By utilizing mock servers, you can spin up demo versions of your SaaS software, even those that normally rely on third-party services, and allow users to play around with it. By using a good mock server implementation, it’s highly likely that users of the demo app won’t even know it’s not making calls to a “real” back end.
Prepare for the Implementation
Before you dive into the technical details of how to set up a mock server, it’s important to take a step back and plan the implementation.
First of all, you’ll need to establish your use case for a mock server. What problem are you trying to solve? What are your goals for the mock server?
Once you know how you’ll be using the mock server, you can start identifying the APIs you need to mock. Though this step might be less relevant if you’re only mocking one API, it can be very helpful when planning the infrastructure for mocking multiple APIs.
With the knowledge of what APIs to mock, you can determine the responses you need. If you’re manually configuring the responses, this step is crucial. Rushing through this step can lead to a lot of time wasted configuring responses you don’t need. If you’re generating requests from a schema, you want to ensure the schema is up-to-date.
At this point, you should have a fairly solid idea of what your mock server will look like and you can start planning for the number of requests your mock server will receive. Although a mock server will typically respond with static data, it’ll still consume resources, and by getting a rough idea of how many requests you expect the mock server to handle, you can ensure that the performance of your mock server is satisfactory and realistic.
By now you’re very close to being ready for the implementation of your mock server, with only one last crucial consideration: How will your mock server handle data?
If your mock server has to return static files—such as text files—you’ll also need to consider the mock server’s storage capabilities. If it has to mock database transactions, how will you implement it? Are the data amounts small enough that they can be kept in memory? Or will you have to hook up some sort of lightweight database?
In general, how to handle data is one of the least-considered and most important aspects of building a mock server. In the end, the goal of a mock server is to simulate the real world as closely as possible.
What Makes a Mock Server Good?
A bad mock server can end up souring the entire developer experience. At worst, it can invalidate all of your testing if it’s returning misconfigured responses. There are certain characteristics you can look out for when determining what mock server to use.
Ease of use
A good mock server shouldn’t complicate the test procedure. Instead, it needs to be fairly easy for developers to get started with, as well as making it easy to create, manage, and modify mocks.
The prevailing reputation of mocks is that they’re difficult to build, frustrating to configure, and laborious to maintain, with some organizations stating that for a given amount of effort X to build mocks, it takes 5 times the effort to update mocks on every release.
For this exact reason, ease-of-use is a crucial aspect of a good mock server, but more on that later.
Interoperability with existing infrastructure
A good mock server should have the capability of being implemented in a continuous manner. Meaning, it can be implemented in CI/CD pipelines, testing frameworks, monitoring tools, etc.
Mocks real-world responses
It’s been mentioned a few times throughout this post, but making sure that the mock server provides realistic responses is paramount to achieving success with mock servers.
Allows for modifications
Though mocking real-world responses is fundamental to a good mock server, it should also allow for modifications. At times, you’ll want to test how your error handling works, or how the application responds to chaos such as latency spikes or bad responses.
Provides an overall good developer experience
A good mock server should provide a smooth and enjoyable experience for developers. If developers are getting frustrated by the mock server, there’s a high likelihood that they’ll either try to avoid using it or keep it to a bare minimum.
Having a good mock server is critical to the success of your implementation. You should be able to use it as a way of testing your applications against a realistic environment, remove any reliance on actual services, and detect bugs early—all factors that come together to improve the overall efficiency of the development process, which will lead to a better user experience.
For example, consider a scenario where a developer is building an e-commerce website, and needs to test the checkout process.
Without a mock server, they would need to actually process a transaction through the payment gateway. Not only would this be time-consuming, but also pose a security risk, as real payment details would be involved.
Now, payment gateways—and many other APIs—have considered this and provide developers with sandbox APIs, which are essentially mock servers built and provided by them. That said, using sandbox APIs may lead to issues such as rate-limiting, in which case there’s still reason to use your own mock server.
User Traffic and Mock Servers
User traffic refers to the data that is going between your application and your users’ devices. This can include page views, clicks, downloads, or any other form of engagement that generates a request-response pair.
When it comes to testing, user traffic is incredibly important, as it’s the only real way of creating a realistic test environment. Not only is it near-impossible to replicate all variations in headers and request bodies, user traffic also contains the behavior patterns generated by real humans interacting with your application.
Every developer has tried developing a feature only to discover that there’s a subset of users interacting with it in a way that the developer didn’t anticipate. This is another reason why user traffic is so important.
When you’re manually configuring mock servers—or generating them from a schema—you’re only creating a mock server that aligns with your expectations. Of course, user traffic relates to the users of the application, whereas mock servers relate to the dependencies. However, the principle still stands. I know personally that I’ve read API documentation only to find that the API didn’t work how I expected it to. Because of these uncertainties in how applications and users interact, there really is only one way to create a fully realistic test environment, which is to use real-world traffic.
This is why tools such as Speedscale have a focus on capturing both the incoming and outgoing traffic of your application.
Third-Party or Homebuilt Mock Server
A key step in implementing a mock server is making the choice between using a third-party tool or building one yourself.
Some advantages of using a third-party tool are:
- Access to a wide range of features
- Ease of use and quick setup
- Often more cost-effective than building from scratch
- At least when you factor in the cost of engineering hours
- Technical support from the provider
On the other hand, building your own mock server comes with advantages as well:
- Complete control over functionality and features
- Tailored to meet the specific needs of your project
- Increased flexibility
- No dependencies on third-party providers
Of course, each approach also comes with unique trade-offs. Using a third-party tool may limit your ability to customize the mock server exactly according to your needs. In turn, building your own mock server may require more time and resources than you have available, given the difficulty in enabling other team members to utilize, develop, and maintain mocks when they’re built from scratch; or when they’re composed of open source scripting tools.
In any case, there are certain considerations that have to be made when mocking APIs in Kubernetes. For example, do you need a mock server that can integrate with modern development paradigms like GitOps?
All in all, the choice depends on the specific needs and requirements of your project. It’s important to weigh the advantages and trade-offs between each option and consider all the surrounding factors that may come into play, based on your environment.