Introducing Mockallan: Testing with API-Level Stubs and Mocks
Tags: testing, mocking, rest, http
Published: 2023-11-03 23:37:31

_Stubs_ and _mocks_ are two fundamental concepts to facilitate testing and ensure that code functions correctly.

A _stub_ is a simplified implementation of a component that provides predetermined responses to method calls. _Stubs_ are often used to simulate the behavior of external dependencies, such as databases or web services, by returning predefined data. They focus on providing consistent, controlled responses, allowing developers to isolate the code under test from external dependencies.

A _mock_, on the other hand, is more concerned with behavior verification. It tracks the interactions of the code under test with its dependencies. _Mocks_ can be set with expectations for method calls and parameter values, and they check whether those expectations are met during the test. They help ensure that the code being tested correctly interacts with its dependencies and performs the expected actions.

For a deeper dive into mocks, stubs, and other test doubles, refer to Martin Fowler's popular article [Mocks Aren't Stubs](https://martinfowler.com/articles/mocksArentStubs.html).

## API-Level Stubs and Mocks

[Mockallan](https://github.com/david-domz/mockallan) seamlessly incorporates the concepts of _stub_ and _mock_ into the API domain. As an HTTP server mock, Mockallan allows developers to set up customizable HTTP responses to simulate API behavior, just like stubs provide predefined return values for method calls in unit testing.

In addition, it supports request assertions, enabling the verification of expected API requests, similar to how mocks track and verify method calls.

Let's see how Mockallan supports both stubs and mocks.

## Configuring Stubs

Mockallan allows you to configure responses for specific endpoints. You can define the response status codes, headers, and response body content for different HTTP methods and paths using a JSON file. 

Here's how you can stub an HTTP endpoint for a `GET` request. 

First, create a JSON file and configure an endpoint for a `GET` request to the `/products` endpoint:

```json
{
    "endpoints": [
        {
            "request": {
                "method": "GET",
                "path": "/products"
            },
            "response": {
                "code": 200,
                "headers": {
                    "Content-Type": "application/json"
                },
                "body": {
                    "products": [
                        {
                            "id": 1,
                            "name": "Product A"
                        },
                        {
                            "id": 2,
                            "name": "Product B"
                        }
                    ]
                }
            }
        }
    ]
}
```

Start Mockallan with the stub configuration file:

```bash
python -m mockallan -c stub_config.json
```

Now, you can use _curl_ to make a _GET_ request to the stubbed endpoint:

```bash
curl -X GET http://localhost:8080/products
```

Mockallan will reply with the configured response:

```json
{
    "products": [
        {
            "id": 1,
            "name": "Product A"
        },
        {
            "id": 2,
            "name": "Product B"
        }
    ]
}
```

This enables you to simulate the behavior of external services and APIs in a controlled and predictable manner during your tests.

## Mocking and Assertions

You can use Mockallan's Assertion API to validate that your software under test made the expected requests to the mock server.

Let's see an example of how to place an assertion for the request that we performed few lines above:

```bash
curl -X GET http://localhost:8080/products
```

By specifying the HTTP method and path in a `/assert-called` request, you can ensure that your code interacts with the mock as intended. Use the following _curl_ command to place the assertion:

```bash
curl "http://localhost:8080/assert-called?method=GET&path=/products"
```

Mockallan will reply with an assertion result. If the assertion request returns a 200 status, it means the request was made as expected, and your test has succeeded.

```json
{
	"status": 200,
	"type": "assertion-success",
	"title": "Assertion request GET /assert-called succeeded",
	"detail": "GET /products called 1 time."
}
```

If the request was not made, or if there were discrepancies, the assertion will return a 409 status, indicating that the test has failed:

```json
{
	"status": 409,
	"type": "assertion-error",
	"title": "Assertion request GET /assert-called failed",
	"detail": "Expected GET /products to be called 1 time. Called 0 times."
}
```

This illustrates how Mockallan can be used to validate whether your software under test made the expected requests to the mock server, providing essential feedback and enhancing the reliability of their tests.

Mockallan also offers features like request body matching based on JSON schema validation, XML schema validation, and regular expressions, making it a versatile tool.

In summary, Mockallan provides a comprehensive solution for both stubbing and mocking, allowing you to simulate external dependencies and verify the interactions of your code with those dependencies.

## References

- [Mockallan GitHub repository](https://github.com/david-domz/mockallan)
- [Mocks Aren't Stubs](https://martinfowler.com/articles/mocksArentStubs.html), Martin Fowler