In our previous blog post, we discussed how today's increasingly distributed systems require that testers have a solid knowledge of APIs, how to test them and how to use them for more efficient testing. In this blog post, we will take a look at different test types and techniques that depend on APIs.
Exploratory testing at the API level
Since an API, by nature, is an interface that exposes specific behaviour of (a part of) a software system, they also present a wide range of options for exploratory testing. Just like you would do at the graphical user interface level, you can give inputs to an API that you think are interesting and that you expect to trigger behaviour you want to further explore. Here are a couple of examples of test ideas that you could perform during an exploratory testing session on an API:
"Let's see what happens if I pass in alphanumeric values for path parameters that according to the documentation are supposed to take integers only"
"I wonder what would happen if I pass in a LOT of data in the request body"
"Did the people who designed and developed this API think about proper input sanitizing, or can I perform SQL injection or cross-site scripting through this API?"
Answers to all these questions can be found through exploring your system at the API level.
Writing automated tests for APIs
Since APIs are meant to be consumed by other systems, it is generally a lot easier to write automation at the API level compared to at the GUI level. Add to this the fact that a lot of applications expose business logic through APIs, and you see that API-level automation often hits a sweet spot between tests that are quick to write and to run, and tests that are close to the behaviour as observed by the end user of a system.
No matter if you're using code libraries for API testing (e.g., REST Assured for Java or requests for Python), or you prefer using a low-code API testing solution such as Postman or SoapUI, a high quality set of automated tests at the API level will be an important part of the overall test suite in a lot of situations.
As software systems become ever more distributed, the number of dependencies that you will have to deal with during testing will quickly grow. Often, these dependencies might cause you trouble when you want to run tests. They might be under development themselves, or it's hard to get them in the right state or to access them at all in the first place. In other situations, you want to isolate the behaviour of the component or system you are developing from that of these dependencies.
In both situations, knowing how to mock APIs is a valuable skill. Mocks allow you to set up and simulate the (expected) behaviour of your dependencies, allowing you to test earlier, more and more often than you would be able to do when dealing with the actual dependencies. Nowadays, there are a lot of tools available that you can use to create and use API mocks, ranging from targeted open source libraries like WireMock and Hoverfly, to enterprise-level service virtualization solutions offered by major tool vendors like Tricentis, Parasoft and SmartBear.
Using APIs for other testing purposes
APIs can also be a very useful means of providing support for other types of testing. Here are some examples where an API is not the test target itself, but where it can be used to perform other types of testing and automation more efficiently instead:
- Performing a system health check before starting off a long-running end-to-end test suite running against the GUI
- Setting up test data in bulk to prepare for user acceptance testing
- Checking that data produced in tests at the GUI level has been stored and can be retrieved successfully from the backend system
- Pulling up and analyzing system logs produced in a performance test
Another challenge when testing highly distributed and microservices-based systems is finding an answer to the question.
"Are all components able to communicate with one another, and is it safe to deploy a new version of our component?"
Contract testing is a technique, supported by tools, that can help finding the answer to this question in a more efficient manner. It is complementary to performing functional and acceptance tests at the API level as it does not focus on individual components in a distributed system, but rather on the integration of pairs of these components.
Contract testing (be it consumer-driven, provider-driven or bidirectional) is rapidly growing in popularity now that systems are becoming ever more distributed and development teams face the above question increasingly often.
As you can see in this article, there is a lot to learn as a tester when it comes to APIs. In the next blog post in this series, we'll take a look at some of the challenges that testers typically face when they embark on their API testing journey, or that keep them from setting sail in the first place.