Complete Guide to Webhook Testing
Most webhooks generally follow a fire-and-forget
style of communication. In this type of communication the webhook provider fires the webhook request once, and doesn't care if it is consumed or returns the appropriate status code. This makes webhooks a very delicate communication system, as consumers must ensure they are always ready to receive and process webhook requests without errors.
Because there may not be a second chance to receive a webhook (and even retry systems have limits), the webhook consumption system must be well tested so that it can process the requests without errors.
You also need to ensure that your servers are tested to determine how much load they can handle and how the webhook processing performance can be improved. Testing enables you to make the proper decisions in order to scale your infrastructure to meet the demands of your webhooks.
In this article, we take a look at different types of tests that can be performed to detect and eliminate bugs from webhook processing, help scale appropriately, and improve webhook processing performance.
Unit testing webhooks for logic errors
What are unit tests?
Unit tests help you test the smallest units of your code (i.e. your functions, classes, and modules). The smallest units of your code are tested in isolation. Most unit tests involve providing a defined input and testing the behavior of your code against the expected output.
Let's assume your webhook endpoint handler contains a function that checks for a database record or performs authentication; you want to test said function in a unit test to ensure that it performs as expected.
How to perform unit tests
Unit tests are performed using a testing library, a test runner, and an assertion library. Oftentimes, these 3 main components are bundled in a single testing library. Testing libraries are specific to programming languages — for example, Jest is a full suite testing library for JavaScript codebases, PHPUnit is the most popular testing library for PHP, and Go comes bundled with a testing library.
Details on how to perform unit tests for different codebases are available on their respective testing library documentations.
Some of the tests you will want to perform in unit tests are:
- Check if the expected result is achieved when input is supplied to a function
- Check if calculations within functions/class methods are correct
- Check the behavior of functions when the wrong data or data types are supplied as input
- Check that classes are properly instantiated
- Check that functions that perform database operations keep the data integrity of the application
- …and many more.
Benefits of unit testing webhooks
- It ensures that logic errors are detected and removed from code
- It detects errors and informs on error handling when the wrong type of data is supplied
- It reduces debugging time because you don't need to worry about parts of your code that have been thoroughly tested
Functional testing of webhook workflows
Functional testing is the type of testing that helps you check the entire behavior of your code. Simply put, it tests the sum of the parts. Let's assume you have a webhook endpoint that receives a payment notification and issues a ticket to the customer. This webhook endpoint would most likely do the following:
- Check that the user is available in your database
- Create a ticket entry for the user in the database
- Send an email informing the user about the ticket details
This operation would involve calling a bunch of functions (which we assume you have tested in your unit tests). Functional tests help you check that your endpoint performed all these operations successfully and the expected effect, ticket entry and email to the customer, takes place.
Testing your webhook processing
The first way to functionally test your webhook is to check the webhook request and processing. This test ensures that your webhook gets to the right destination and is processed as expected. For this, you will need a publicly accessible HTTPS endpoint as your webhook URL.
Getting this URL for testing purposes is non-trivial; however, the Hookdeck Test tool provides a webhook URL to test your webhook and inspect its behavior and details in the browser.
Performing functional tests on webhook URLs
Webhook URLs are endpoints on your application's API. Testing a webhook URL requires a setup that can send mock requests to the endpoint and check the output for the expected result(s).
Just like unit tests, the way you write functional tests in your codebase and the libraries required is specific to the programming language/framework you're working in. For example, supertest is a Node.js
library that can be used to test APIs by sending mock requests and checking the outcome.
If you want an API testing framework that can be used for any codebase, then the Postman test suite is highly recommended. Postman has an industry-standard automated testing suite for running tests against your webhook endpoint whether in development, staging, or production environments.
In Postman, you can use your webhook endpoint to build collections mocking different scenarios (success, failure, invalid data, etc.), and write tests for each use case.
Postman tests can be run locally, or automated in a CI/CD pipeline using Postman's command-line utility (Newman) as shown below:
Benefits of functional tests on webhooks
- They help test the workflow involved in processing a webhook
- Webhook idempotency can be checked using functional tests
- Data integrity checks can be performed by inspecting the outcome of webhook processing
- Error checking and error handling of failure situations can be observed
- Authentication checks can also be tested using functional tests
- …and many other workflows and expected outcomes particular to your application can be inspected for errors.
Load testing webhooks for resilience
Load testing is the practice of putting your application under the pressure of network traffic to determine how many requests it can process within a given time without dropping a single one.
Load tests are very essential for applications that need to process a lot of webhooks, as they help you make informed decisions about scaling your application as your traffic grows.
How to load test your webhooks
One of the most used utilities for performing load tests is Apache Benchmark (AB for short). AB is a command-line utility that enables you to run a specified number of requests (hundreds, thousands, etc.) against an API endpoint.
You can specify the number of requests to be fired, the concurrency level, and also the payload.
The AB command below specifies that a thousand requests should be fired at the endpoint [https://myserver.com/webhook-processing](https://myserver.com/webhook-processing)
using a concurrency level of 20 and passing data from a data.json
file in JSON format.
ab -n 1000 -c 20 -p data.json -T application/json -rk https://myserver.com/webhook-processing
Some of the information that AB gives you after it completes the requests includes:
- Total number of requests executed per second
- Total number of completed requests
- Total number of failed requests
- Average time per request
Below is an example of the report from running AB on an endpoint:
This is all useful information for engineers looking to scale their webhook infrastructure.
If you want a more specialized load testing tool to cover more use cases, you can check out K6, JMeter (also by Apache), and Gatling.
Benefits of load testing webhooks
- It helps determine the capacity of your server
- It helps in determining rate-limiting settings
- For horizontal scaling, it helps in making decisions about adding more servers to handle increasing traffic
- It helps determine when to introduce an asynchronous processing component like message queues
Profiling webhooks for performance improvements
Profiling is the practice of sampling a portion of your code to look for performance bottlenecks. Tasks performed in code involve several micro-operations which can be represented by a call stack. When a performance dip is noticed, for example, slow running operations or high request per second metrics, it's very important to profile the webhook processing code for any performance bottlenecks.
These bottlenecks could be due to long-running functions (cryptographic functions, hashing functions, etc.) in the call stack causing the webhook operation to be slow.
How to profile webhook code
Profiling is done by using a profiler. A profiler is a tool that measures how some piece of code consumes system resources at runtime. The profiler helps you find performance bottlenecks and understand the code's behavior.
When a profiler is active, you need to run the code to get results. For example, you can send a series of requests to the webhook URL while the profiler is watching, then collate results once the requests are complete.
Profilers are mostly directly related to programming languages, however some profilers now exist that support different languages. Node.js has a built-in profiler that can be used alongside Apache Benchmark. An example of a multi-language profiler is Blackfire, which currently supports Go, PHP, and Python.
Reports from profilers show you how much of your resources are being consumed and which code in the call stack is consuming them. This provides data on functions that need to be optimized for better performance.
One of the reports profilers can provide is Flame graphs. A Flame graph is a call stack visualization in the form of a flame that uses color densities to depict "hot zones" in CPU usage. Below is an example of a Flame graph:
Each horizontal bar represents an operation in the call stack; the length of the bar indicates the time it takes the code to execute. The longer the bar, the more time code execution takes, which can be a good indicator of where performance improvement is needed. The density of the colors indicates how CPU-intensive the operation is, which is another indication of where performance optimization is required.
Benefits of profiling webhook performance
- Helps detect where the performance bottlenecks are located
- Helps you make better decisions on how to vertically scale the server
- Indicates the synchronous operations that can be made asynchronous to improve performance
Conclusion
Testing is a very powerful engineering practice that helps build stable codebases and boost reliability. However, understanding the benefits of testing is the best way to be convinced to make it part of your development workflow. In this article, we have looked at how to test our webhooks for reliability, and the loads of benefits that come with it.
Testing webhooks helps you build highly reliable and performant webhooks which gives you more confidence and fewer bugs to fix.
Happy coding!
Gain control over your webhooks
Try Hookdeck to handle your webhook security, observability, queuing, routing, and error recovery.