Streamlining Java Unit Testing with Mockito, MockServer, and Cobertura

Mock objects isolate unit tests from external dependencies, ensuring consistent execution regardless of network availability or database state. The goal is truly portable, self-contained validation logic.

After evaluating several tools, Mockito and MockServer were selected for Java projects. Other candidates were set aside for various reasons:

  • Rap2 and Easy-mock rely on Node.js and lack request timeout/context configuraton.
  • Wiremock functions similar but presents a English-only interface.
  • Postman's mock mode generates random, unpredictable port and URL assignments.
  • MockServer, built on Netty with a native Java core, offers high adaptability for Java teams.

Mockito

Mockito, bundled with spring-boot-starter-test, allows simulation of object behavior. It eliminates the need for real RPC calls, databases, or utilities.

  • Mock returns a bare object; unconfigured method calls yield null or an exception.
  • Spy wraps a real object, invoking the original method for any behavior not explicitly stubbed.

Spring Integration

Add the dependency:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-all</artifactId>
    <version>1.9.5</version>
    <scope>test</scope>
</dependency>

Initialize mocks and swap the Spring-managed bean:

@Mock
RemotePaymentClient paymentClient;

@Autowired
OrderPaymentFacade orderPaymentFacade;

@Before
public void prepareMocks() throws Exception {
    MockitoAnnotations.initMocks(this);
    ReflectionTestUtils.setField(
        AopTargetUtils.getTarget(orderPaymentFacade),
        "paymentClient",
        paymentClient
    );
    PaymentResult mockResult = new PaymentResult();
    when(paymentClient.queryByCardId("101010")).thenReturn(mockResult);
}

For Spring Boot 2.0+, simply annotate the field with @MockBean; the framework handles replacement automatically.

MockServer

MockServer simulates full HTTP environments, helping catch protocol-level issues. It can run embedded in test lifecycles or as a standalone service.

Setup

<dependency>
    <groupId>org.mock-server</groupId>
    <artifactId>mockserver-netty</artifactId>
    <version>5.11.1</version>
</dependency>

Start the server and define dynamic responses:

private final int mockPort = 20000;
private ClientAndServer mockServer;

@Before
public void startMockServer() {
    mockServer = startClientAndServer(mockPort);
    mockServer
        .when(
            request()
                .withMethod("POST")
                .withPath("/gateway/payment/charge")
                .withContentType(MediaType.APPLICATION_JSON)
        )
        .respond(new FlexibleCallback());
}

public static class FlexibleCallback implements ExpectationResponseCallback {
    private final Gson gson = new Gson();

    @Override
    public HttpResponse handle(HttpRequest req) {
        if (!req.getMethod().getValue().equals("POST")) {
            return notFoundResponse();
        }
        if (!verifySignature(req)) {
            return jsonError("SIGNATURE_VERIFY_FAIL");
        }
        return buildResponse(req);
    }

    private HttpResponse buildResponse(HttpRequest req) {
        JSONObject body = JSON.parseObject(new String(req.getBodyAsRawBytes()));
        Assert.assertNotNull(body.getString("merchant_id"));
        String merchantId = body.getString("merchant_id");
        String respBody = "{\"success\": true,\"code\": \"0000\",\"data\": {\"user\": \"" + merchantId + "\"}}";

        // Simulate async callback after delay
        new Thread(() -> {
            LockSupport.parkNanos(2_000_000_000L);
            String notifyUrl = body.getString("notify_url");
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(org.springframework.http.MediaType.APPLICATION_JSON);
            JSONObject payload = new JSONObject();
            payload.put("status", "finished");
            new RestTemplate().postForObject(notifyUrl,
                new HttpEntity<>(payload.toJSONString(), headers), String.class);
        }).start();

        return response().withStatusCode(200).withBody(respBody);
    }

    private boolean verifySignature(HttpRequest req) {
        String sig = req.getFirstHeader("X-Signature");
        String raw = new String(req.getBodyAsRawBytes(), StandardCharsets.UTF_8);
        String md5 = DigestUtils.md5Hex(raw.getBytes(StandardCharsets.UTF_8));
        return RSAUtils.doCheck(md5, sig, privateKey, StandardCharsets.UTF_8.displayName());
    }

    private HttpResponse jsonError(String msg) {
        return response().withStatusCode(200).withBody(gson.toJson(Map.of("msg", msg)));
    }
}

Cobertura Coverage Reports

Cobertura integrates with Maven to produce branch and line coverage metrics.

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>cobertura-maven-plugin</artifactId>
    <version>2.7</version>
</plugin>

Run with:

mvn clean cobertura:cobertura -f pom.xml

Open target/site/index.html to inspect the coverage dashboard.

Tags: java Unit Testing Mockito MockServer Cobertura

Posted on Wed, 05 Aug 2026 17:07:34 +0000 by cyberRobot