Why does `Mockito.mockConstruction` not return the mocked object in my JUnit 5 test?

I am trying to replace PowerMockito with Mockito 4.x for mocking constructors using mockConstruction.

However, the mocked object is not returned, and the code inside the try block does not execute as expected.

Example setup:

@BeforeEach
void setUp() {
    partUnlinkService = spy(new PartVideoUnlinkService(part1, part2, part3));
}

Test method:

@Test
void shouldThrowException() throws Exception {
    UrlLinkDto urlLinkDto = UrlPartLinkDto.builder().callId("333").videoId("5555544").build();
    ArgumentCaptor<UrlPartLinkDto> argumentCaptor = ArgumentCaptor.forClass(UrlPartLinkDto.class);

    try (MockedConstruction<ObjectMapper> ignoredVariable = mockConstruction(ObjectMapper.class,
            (objectMapper, context) -> {
                partUnlinkService.unlink(urlLinkDto, false);
                verify(partLogCheckService, times(1)).checkForExistingVideo(urlLinkDto.getVideoId());
                verify(objectMapper, times(1)).writeValueAsString(argumentCaptor.capture());
                Throwable throwable = catchThrowable(() -> objectMapper.writeValueAsString(argumentCaptor.capture()));
                assertThat(throwable).isInstanceOf(JsonProcessingException.class);
            })) {
    }
}

The mocked ObjectMapper is not returned, preventing verification inside the block.

How can I correctly use mockConstruction to capture and assert the mocked object’s behavior?

I struggled with mockConstruction not returning the mocked object too. The trick is to not call new ObjectMapper() inside your service before the mock is active.

In Mockito 4, the constructor mock only works for instances created while the MockedConstruction is active.

Also, inside the callback (objectMapper, context) -> { ... }, the lambda is only called when a new instance is created, so calling unlink() inside that lambda won’t capture your actual call unless the new instance is created there.

Instead, try this pattern:

try (MockedConstruction<ObjectMapper> mocked = mockConstruction(ObjectMapper.class)) {
    partUnlinkService.unlink(urlLinkDto, false);

    ObjectMapper mockInstance = mocked.constructed().get(0);
    verify(mockInstance).writeValueAsString(any());
}

I had to move the unlink() call inside the try block but outside the lambda, and it worked perfectly.

From my experience, a common misunderstanding with mockConstruction is expecting the lambda (objectMapper, context) -> { ... } to “replace” the object globally.

It doesn’t, it’s only a hook that runs whenever a new instance is created inside the try-block.

So if your service creates new ObjectMapper() before entering the block, the mock never applies. I usually do this:

Ensure all constructor calls happen inside the try block.

Use mocked.constructed() to get the mocked instances for verification.

Example:

try (MockedConstruction<ObjectMapper> mocked = mockConstruction(ObjectMapper.class)) {
    partUnlinkService.unlink(urlLinkDto, false); // creates new ObjectMapper -> now mocked

    // get the first constructed mock
    ObjectMapper mockMapper = mocked.constructed().get(0);
    verify(mockMapper).writeValueAsString(any());
}

This reliably lets me capture the instance and run assertions. I also avoid putting unlink() inside the lambda, which I used to do mistakenly.

I ran into the same issue when migrating from PowerMockito whenNew() to Mockito 4’s mockConstruction. The key thing I learned is that mockConstruction only replaces new object creation inside the try-with-resources block.

That means if your code instantiates the object outside the block, Mockito won’t intercept it.

In your example, partUnlinkService.unlink() probably creates a new ObjectMapper before the mocked construction is active.

A simple fix is to wrap the actual code that creates the instance inside the mockConstruction block, like this:

try (MockedConstruction<ObjectMapper> mocked = mockConstruction(ObjectMapper.class)) {
    ObjectMapper mapper = new ObjectMapper(); // This instance is now mocked
    partUnlinkService.unlink(urlLinkDto, false);

    ObjectMapper mockInstance = mocked.constructed().get(0); // capture the mocked instance
    verify(mockInstance, times(1)).writeValueAsString(any());
}

Notice that I directly get the mocked instance via mocked.constructed(). That way you can verify and assert behavior.