Fundamentals 22 min read

How Mockito Powers Java Unit Tests: Deep Dive into Annotations and Mocking Mechanics

This article explains the core concepts of the Mockito framework, compares it with other Java unit‑testing tools, demonstrates practical code examples, and breaks down the internal workings of annotations like @InjectMocks, @Mock, @RunWith, as well as the Mockito.when() and Mockito.verify() mechanisms.

Alibaba Cloud Developer
Alibaba Cloud Developer
Alibaba Cloud Developer
How Mockito Powers Java Unit Tests: Deep Dive into Annotations and Mocking Mechanics

Good unit tests not only validate code design but also catch bugs early, preventing production risks. This article starts from common unit‑testing frameworks and provides an in‑depth, easy‑to‑understand guide to the Mockito framework.

Unit‑Testing Frameworks

Java offers many unit‑testing frameworks, each with its own strengths. The most widely used are:

JUnit – the most popular framework, offering rich assertions and, since JUnit 5, features like dynamic tests and dependency injection.

TestNG – inspired by JUnit but adds advanced capabilities such as test suites, data‑driven tests, dependencies, and parallel execution.

Spock – a Groovy‑based framework that combines features from JUnit, jMock, RSpec, and others, providing a highly expressive DSL.

Mockito – focuses on creating and verifying mock objects; it is typically used together with JUnit or TestNG.

EasyMock – generates mock objects via Java proxies, allowing recording, replay, and verification of method calls.

PowerMock – extends other mocking frameworks to mock static, private, final methods and constructors, though it may introduce compatibility issues.

JMock – a lightweight BDD‑style framework for mocking interfaces or classes.

In our organization, Mockito is the mainstream choice. The typical test flow is illustrated below:

Example Test Code

<span>@Autowired</span>
<span>private BenefitRecordQueryServiceI benefitRecordQueryServiceI;</span>
<span>@Override</span>
<span>public List<BenefitRecordExtendVO> queryBenefitRecordList(Long companyId, String scene) {</span>
    Validate.notNull(companyId, "companyId cannot be null");
    Validate.notBlank(scene, "scene cannot be null");
    BenefitRecordQueryParam param = new BenefitRecordQueryParam();
    param.setCompanyId(companyId);
    param.setScene(scene);
    MultiResponse<BenefitRecordExtendDTO> res = benefitRecordQueryServiceI.pageQueryBenefitRecordWithExtendAttrs(param);
    if (res == null || !res.isSuccess()) {
        log.error("pageQueryBenefitRecordWithExtendAttrs error, companyId:{}, scene:{}, res:{}", companyId, scene, JSON.toJSONString(res));
        throw new SupplierFosterException("pageQueryBenefitRecordWithExtendAttrs error");
    }
    return DataObjectUtils.transferDeep(res.getData(), BenefitRecordExtendVO.class);
}
<span>@InjectMocks</span>
<span>private BenefitAdaptorImpl benefitAdaptor;</span>

<span>@Mock</span>
<span>private BenefitRecordQueryServiceI benefitRecordQueryServiceI;</span>

<span>@Test</span>
<span>public void testQueryBenefitRecordListWhenSuccess() {</span>
    Long companyId = 123L;
    String scene = "cnfm";
    MultiResponse<BenefitRecordExtendDTO> res = new MultiResponse<>();
    List<BenefitRecordExtendDTO> resList = new ArrayList<>();
    BenefitRecordExtendDTO dto = new BenefitRecordExtendDTO();
    dto.setBenefitCode("rfq");
    resList.add(dto);
    res.setSuccess(true);
    res.setData(resList);
    Mockito.when(benefitRecordQueryServiceI.pageQueryBenefitRecordWithExtendAttrs(Mockito.any()))
           .thenReturn(res);
    List<BenefitRecordExtendVO> result = benefitAdaptor.queryBenefitRecordList(companyId, scene);
    Assert.assertEquals(1, result.size());
    BenefitRecordExtendVO benefitRecordRes = result.get(0);
    Assert.assertNotNull(benefitRecordRes);
    Assert.assertEquals("rfq", benefitRecordRes.getBenefitCode());
    Mockito.verify(benefitRecordQueryServiceI).pageQueryBenefitRecordWithExtendAttrs(Mockito.any());
}

The article then poses four key questions about the annotations used in the example, encouraging readers to reflect on their understanding.

@RunWith(MockitoJUnitRunner.class)

This JUnit annotation automatically initializes mock objects, replacing the manual MockitoAnnotations.initMocks(this) call required before version 1.9.5.

@InjectMocks

@InjectMocks automatically injects mock objects into the class under test, using constructor injection first, then field injection, and finally setter injection if needed.

@Mock

@Mock creates a mock instance for a field, allowing configuration of default answers, stubbing behavior, naming, extra interfaces, and serializability.

Mockito.when() and thenReturn()

Mockito.when() sets up stubbing for a mock method call. The call creates an OngoingStubbing object, which records the expected behavior (e.g., thenReturn()) and registers it in a thread‑safe stub list.

Mockito.verify()

Mockito.verify() creates a verification mode (default is once) and checks whether the specified method on the mock was invoked with the expected arguments.

Finally, the article concludes that it has covered the essential inner workings of Mockito’s annotation processing, mock creation, stubbing, and verification, inviting readers to explore further on their own.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

unit testingMockingannotationsJUnitMockitoTestNG
Alibaba Cloud Developer
Written by

Alibaba Cloud Developer

Alibaba's official tech channel, featuring all of its technology innovations.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.