Mockito
Unit Testing
Java
Software Development
Object-Oriented Programming

Mockito how to verify method was called on an object created within a method?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

If a method creates a collaborator with new internally, Mockito cannot verify calls on that object unless you change the design or use construction mocking. The cleanest long-term answer is usually to refactor the code so the collaborator is injected, because that makes the code both testable and easier to evolve.

Why Direct Verification Fails

Suppose you have code like this:

java
1public class NotificationService {
2
3    public void sendAlert(String message) {
4        EmailService emailService = new EmailService();
5        emailService.sendEmail("[email protected]", message);
6    }
7}

In a test, you do not have a reference to the EmailService instance created inside sendAlert. Since Mockito verifies interactions on mocks or spies you control, there is nothing to verify directly here.

That is the core problem. The object exists, but your test cannot substitute or observe it easily.

Best Design Fix: Inject the Collaborator

The most maintainable solution is to move object creation outside the method and inject the dependency.

java
1public class NotificationService {
2
3    private final EmailService emailService;
4
5    public NotificationService(EmailService emailService) {
6        this.emailService = emailService;
7    }
8
9    public void sendAlert(String message) {
10        emailService.sendEmail("[email protected]", message);
11    }
12}

Now the test is straightforward:

java
1import static org.mockito.Mockito.mock;
2import static org.mockito.Mockito.verify;
3
4public class NotificationServiceTest {
5
6    @org.junit.jupiter.api.Test
7    void verifyEmailSent() {
8        EmailService emailService = mock(EmailService.class);
9        NotificationService service = new NotificationService(emailService);
10
11        service.sendAlert("Emergency!");
12
13        verify(emailService).sendEmail("[email protected]", "Emergency!");
14    }
15}

This is usually the best answer because it improves the production design, not just the test.

Factory Injection When Construction Is Still Needed

Sometimes you want the class to keep creating new instances, but you still want control in tests. A factory abstraction is a good compromise.

java
public interface EmailServiceFactory {
    EmailService create();
}

Use it in the service:

java
1public class NotificationService {
2
3    private final EmailServiceFactory factory;
4
5    public NotificationService(EmailServiceFactory factory) {
6        this.factory = factory;
7    }
8
9    public void sendAlert(String message) {
10        EmailService emailService = factory.create();
11        emailService.sendEmail("[email protected]", message);
12    }
13}

And test it:

java
1import static org.mockito.Mockito.mock;
2import static org.mockito.Mockito.verify;
3import static org.mockito.Mockito.when;
4
5public class NotificationServiceTest {
6
7    @org.junit.jupiter.api.Test
8    void verifyEmailSent() {
9        EmailService emailService = mock(EmailService.class);
10        EmailServiceFactory factory = mock(EmailServiceFactory.class);
11        when(factory.create()).thenReturn(emailService);
12
13        NotificationService service = new NotificationService(factory);
14        service.sendAlert("Emergency!");
15
16        verify(emailService).sendEmail("[email protected]", "Emergency!");
17    }
18}

This keeps the “create a new object” behavior while still making tests deterministic.

Construction Mocking as a Tactical Option

Modern Mockito can also mock object construction. That can be useful when you cannot refactor immediately.

java
1import static org.mockito.Mockito.mockConstruction;
2import static org.mockito.Mockito.verify;
3
4import org.mockito.MockedConstruction;
5
6public class NotificationServiceTest {
7
8    @org.junit.jupiter.api.Test
9    void verifyEmailSent() {
10        try (MockedConstruction<EmailService> mocked = mockConstruction(EmailService.class)) {
11            NotificationService service = new NotificationService();
12            service.sendAlert("Emergency!");
13
14            EmailService constructed = mocked.constructed().get(0);
15            verify(constructed).sendEmail("[email protected]", "Emergency!");
16        }
17    }
18}

This can be very helpful in legacy code, but it should not be your first design choice for ordinary code. Construction mocking is more intrusive and often a sign that the class under test has too much responsibility.

Choose the Right Approach

A practical rule is:

  • refactor to dependency injection if you control the code and can improve the design
  • use a factory when creation is part of the business flow
  • use construction mocking mainly for legacy or hard-to-change code

That keeps your tests both effective and maintainable.

Common Pitfalls

The most common pitfall is trying to verify a real object that was created internally without first introducing some seam for testing. Mockito cannot verify what it does not control.

Another mistake is reaching for advanced construction mocking before considering a simple design refactor. Often the design fix is cleaner than the testing trick.

A third issue is overusing factories just for tests when straightforward constructor injection would do.

Finally, some teams write tests around internal construction details when the better test target is the externally visible behavior. Verify interactions only when they truly matter to the unit’s contract.

Summary

  • You usually cannot directly verify a method call on an object created with new inside the method under test.
  • The best fix is often to inject that collaborator instead of constructing it internally.
  • A factory is a good middle ground when object creation is still part of the logic.
  • Mockito construction mocking can help in legacy code, but it should not be the default design strategy.
  • Good testability usually comes from better dependency boundaries, not from more complicated mocks.

Course illustration
Course illustration

All Rights Reserved.