# Testing Repositories and HTTP Clients — JUnit 5 & Mockito

Source: https://www.skillbyai.com/en/java-testing/s-jpa-web

> Write @DataJpaTest tests and test outgoing HTTP calls with mock servers.

## Testing the edges of the application

Two kinds of edges deserve focused tests. **Repositories**: `@DataJpaTest` loads JPA infrastructure and runs each test in a rolled-back transaction; combine it with Testcontainers (`@AutoConfigureTestDatabase(replace = NONE)`) so queries run on the production database engine. Use `TestEntityManager` to set up data, then call **`flush()` and `clear()`** before asserting, so you test what the database returns rather than cached objects. Test custom queries, constraints and mappings, not Spring Data's built-in `save` and `findById`. **Outgoing HTTP calls**: test your client classes against a **mock HTTP server** rather than mocking the HTTP library. Options include **WireMock** (a standalone or JUnit-integrated HTTP stub server), **MockWebServer** from OkHttp, and Spring's **`@RestClientTest`** with `MockRestServiceServer` for `RestClient` and `RestTemplate`. These tests check URLs, headers, JSON mapping, error handling and timeouts, the things that most often break in integrations.

## Testing an HTTP client with WireMock

The real client code talks to a local stub server over HTTP.

```java
@WireMockTest
class ExchangeRateClientTest {

    @Test
    void parsesRateFromProvider(WireMockRuntimeInfo wm) {
        stubFor(get(urlPathEqualTo("/v1/rates"))
            .withQueryParam("base", equalTo("USD"))
            .willReturn(okJson("{\"base\":\"USD\",\"rates\":{\"INR\":83.2}}")));

        var client = new ExchangeRateClient(wm.getHttpBaseUrl(), Duration.ofSeconds(2));

        assertThat(client.rate("USD", "INR")).isEqualByComparingTo("83.2");
        verify(getRequestedFor(urlPathEqualTo("/v1/rates")).withHeader("Accept", containing("json")));
    }

    @Test
    void providerErrorBecomesDomainException(WireMockRuntimeInfo wm) {
        stubFor(get(urlPathEqualTo("/v1/rates")).willReturn(serverError()));
        var client = new ExchangeRateClient(wm.getHttpBaseUrl(), Duration.ofSeconds(2));

        assertThatThrownBy(() -> client.rate("USD", "INR"))
            .isInstanceOf(RatesUnavailableException.class);
    }
}
```

## Test the failure paths of integrations

Most production incidents in integrations come from errors, timeouts and unexpected payloads, not from the happy path. Stub 500s, slow responses and malformed JSON, and assert your client handles each one.

**Quiz:** Why test an HTTP client against WireMock rather than mocking the HTTP library?

- [ ] WireMock is required by Spring
- [ ] Mocking HTTP libraries is impossible
- [x] It exercises real HTTP serialisation, URLs, headers and error handling through the actual client code
- [ ] WireMock makes tests skip network code

*Answer:* It exercises real HTTP serialisation, URLs, headers and error handling through the actual client code. A local stub server tests the real request and response handling end to end.
