How to Create and Use a Custom ResultMatcher for Date Testing with MockMvc
Tags: tutorial, java, testing, spring
Published: 2024-01-17 12:00:00


In this tutorial, you will learn how to create a custom ResultMatcher for MockMvc, to suit your project needs.

Imagine you are testing an API and the response contains a date. And you want to check if the response date is valid.

So you have a test assertion that checks for an exact date and time. But for some reason, this result can vary over time. For some reasons:

- Maybe your machine has a different timezone from what’s used in the server.
- Maybe some parts of your code can use different time zones.
- Maybe your code has a business rule that has to calculate a date and time that can vary in a range.
- Maybe you are using LocalDateTime.now() and you cannot mock using the `Clock`.
- Or any specific other date manipulation or configuration that your project has.

When you run your tests you get errors like this, you check for the `LocalDateTime.now()` but the result is a few seconds later.

```java
Expected: is "2024-01-11T12:37:03.1"
but: was "2024-01-11T12:38:21.1"
```

Or you have a time zone issue that makes everything 3 hours behind:

```java
Expected: is "2023-03-07T20:18:57"
but: was "2023-03-07T17:18:57"
```

One solution for that (there are more solutions, maybe some better ones) is to create a custom ResultMatcher. That can check if the result date from an API response is in a range.

## How to use a custom result matcher to fix this issue?

If we are checking the MockMvc the code should look like this:

```java
mvc.perform(get("/product/{}",productId).contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.date", is("2023-03-07T17:18:57")));
```

As we said, the problem with this implementation is that the assertion is by the exact date and time. 

And our time can vary a little bit, so it’ll break our test.

Writing a custom result matcher will enable you to do custom checks as you need.

You can write a result matcher that checks if the response date is in a range that you specify.

### Example of a custom result matcher for date range validation:

```java
public static ResultMatcher isDateTimeInRange(String path, String startDateStr, String endDateStr) {
        LocalDateTime startDate = LocalDateTime.parse(startDateStr, formatter);
        LocalDateTime endDate = LocalDateTime.parse(endDateStr, formatter);
        return mvcResult -> {
            String contentAsString = mvcResult.getResponse().getContentAsString();
            LocalDateTime checkoutDate = LocalDateTime.parse(JsonPath.read(contentAsString, path), formatter);
            if (!(checkoutDate.isAfter(startDate) && checkoutDate.isBefore(endDate))) {
                throw new AssertionError(String.format("Date: %s is not between %s and %s", checkoutDate, startDate, endDate));
            }
        };
    }
```

This code allows us to send a start and end range and the date format for the date we’re working. 

This will enable us to write our logic to check if the date is in range!

### How to use your custom result matcher in your test

```java
mvc.perform(get("/product/{}",productId).contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(status().isOk())
                .andExpect(isDateTimeInRange("$.date",
                                "2019-03-07T13:18:57",
                                "2019-03-07T21:18:57",
                                "yyyy-MM-dd'T'HH:mm:ss"));
```

This will check if the response date is in the range requested!

By the way, this is only one example of how to create a custom result matcher. 

Explore the possibilities and create some that suit your needs.

Happy coding!

Follow me on social media, and here on dev.to! 

[Willian Moya (@WillianFMoya) / X (twitter.com)](https://twitter.com/WillianFMoya)

[Willian Ferreira Moya | LinkedIn](https://www.linkedin.com/in/willianmoya/)