You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Mockito Mock通过new关键字创建的对象(不使用PowerMock)

好问题!Mockito本身确实没办法直接Mock方法内部new出来的对象,但咱们完全可以通过重构代码提升可测试性的方式解决,根本不需要PowerMock。针对你给出的EventPublisher代码,我给你两种可行的方案:

方案1:依赖注入(最推荐,符合依赖倒置原则)

思路

把ObjectMapper从方法内部创建改为外部注入,这样测试时可以直接传入Mock的ObjectMapper实例,彻底避免在方法内部硬编码创建依赖的问题,同时让代码耦合度更低。

修改后的业务代码

public class EventPublisher {
    // 将ObjectMapper作为成员变量,通过构造方法注入
    private final ObjectMapper objectMapper;

    // 提供构造方法,用于外部注入ObjectMapper
    public EventPublisher(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    public void publishEvent(final String eventJson) {
        try {
            // 直接使用注入的ObjectMapper,不再调用内部创建方法
            // 注:原代码里的`event`变量看起来是笔误,这里假设你是要处理传入的eventJson
            Test testJson = objectMapper.readValue(eventJson, Test.class);
            testJson.getName();
        } catch (JsonProcessingException e) {
            return;
        }
        // publish(); some external call
    }

    // 如果其他地方仍需要创建特定配置的ObjectMapper,可以保留此方法,基于注入的实例做调整
    private ObjectMapper getObjectMapper(boolean someFlag) {
        return objectMapper.copy().enable(SerializationFeature.INDENT_OUTPUT);
    }
}

测试代码

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
public class EventPublisherTest {

    @Mock
    private ObjectMapper mockObjectMapper; // Mock ObjectMapper实例

    @InjectMocks
    private EventPublisher eventPublisher; // 自动将Mock的ObjectMapper注入到EventPublisher

    @Test
    public void testPublishEvent_WhenJsonProcessingFails_ReturnsEarly() throws JsonProcessingException {
        // 模拟JSON解析失败的场景
        String testEventJson = "{invalid-json}";
        doThrow(JsonProcessingException.class).when(mockObjectMapper)
                .readValue(testEventJson, Test.class);

        // 调用目标方法
        eventPublisher.publishEvent(testEventJson);

        // 验证后续的外部调用(比如publish())没有被执行(如果需要的话)
        // verify(eventPublisher, never()).publish();
    }
}

方案2:重构创建方法为protected,用Mockito Spy替换返回值

思路

如果不想大幅修改现有代码结构,可以把创建ObjectMapper的getObjectMapper方法访问权限从private改为protected,这样测试时可以用Mockito的Spy来监视EventPublisher实例,并覆盖这个方法的返回值,返回我们Mock的ObjectMapper。

修改后的业务代码

public class EventPublisher {
    public void publishEvent(final String eventJson) {
        try {
            ObjectMapper objectMapper = getObjectMapper(true);
            // 同样修正笔误,假设处理传入的eventJson
            Test testJson = objectMapper.readValue(eventJson, Test.class);
            testJson.getName();
        } catch (JsonProcessingException e) {
            return;
        }
        // publish(); some external call
    }

    // 将private改为protected,允许子类(包括Spy生成的动态子类)重写
    protected ObjectMapper getObjectMapper(boolean someFlag) {
        ObjectMapper mapper = new ObjectMapper();
        if (someFlag) {
            // 原有的配置逻辑
            mapper.enable(SerializationFeature.INDENT_OUTPUT);
        }
        return mapper;
    }
}

测试代码

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
public class EventPublisherTest {

    @Spy
    private EventPublisher eventPublisherSpy; // Spy真实的EventPublisher实例

    @Test
    public void testPublishEvent_WithMockedObjectMapper() throws JsonProcessingException {
        // 创建Mock的ObjectMapper
        ObjectMapper mockMapper = mock(ObjectMapper.class);
        // 当调用getObjectMapper(true)时,返回我们的Mock实例
        doReturn(mockMapper).when(eventPublisherSpy).getObjectMapper(true);

        // 模拟JSON解析后的Test对象行为
        Test mockTestObj = mock(Test.class);
        when(mockMapper.readValue(anyString(), eq(Test.class))).thenReturn(mockTestObj);

        // 调用目标方法
        eventPublisherSpy.publishEvent("valid-event-json");

        // 验证Test对象的getName()方法被调用
        verify(mockTestObj).getName();
    }
}

额外说明

  • 方案1是更优的选择,它不仅解决了测试问题,还让代码更符合面向对象设计原则,后续维护和扩展也更方便。
  • 原代码里的event变量看起来是笔误,我在示例中假设你要处理的是传入的eventJson,你可以根据实际业务调整。

内容的提问来源于stack exchange,提问作者Kiran

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:25:03