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

如何测试含多依赖的Spring组件?解决JUnit测试NPE问题

问题分析

你遇到的NullPointerException核心原因是:测试过程中CacheService的实例没有被Spring容器管理,或者手动实例化时未注入其内部的genericBean和dao依赖。如果直接通过new CacheService()创建对象,Spring不会自动处理字段上的@Autowired注入,导致这些依赖为空。另外注意你的代码存在一处笔误:Transformer的doAction方法调用了cacheService.perform(o),但CacheService中定义的方法是doAction(CustomObject o),需要先统一方法名才能正常运行。

解决方案

方案1:通过Spring上下文加载完整依赖(集成测试)

如果需要验证整个依赖链的真实行为,使用Spring Boot Test相关注解让容器自动管理所有Bean的注入:

@SpringBootTest
class TransformerTest {
    @Autowired
    private Transformer transformer;

    @Test
    void doAction_ShouldExecuteSuccessfully() {
        CustomObject testObj = new CustomObject();
        transformer.doAction(testObj);
        // 添加你的断言逻辑,比如验证dao的fetch方法被调用
    }
}

如果只想加载特定组件的上下文(避免启动完整应用),可以用@ContextConfiguration指定需要的Bean:

@ContextConfiguration(classes = {Transformer.class, CacheService.class, GenericBean.class, Dao.class})
@ExtendWith(SpringExtension.class)
class TransformerTest {
    @Autowired
    private Transformer transformer;

    // 测试方法...
}

方案2:用Mockito模拟依赖(纯单元测试)

如果只需要测试Transformer的逻辑,不关心CacheService内部依赖的真实行为,用Mockito模拟相关依赖即可:

方式A:模拟CacheService的内部依赖

@ExtendWith(MockitoExtension.class)
class TransformerTest {
    @Mock
    private Dao mockDao;
    @Mock
    private GenericBean mockGenericBean;
    @InjectMocks
    private CacheService cacheService;
    private Transformer transformer;

    @BeforeEach
    void setUp() {
        transformer = new Transformer(cacheService);
    }

    @Test
    void doAction_ShouldCallDaoFetch() {
        CustomObject testObj = new CustomObject();
        transformer.doAction(testObj);
        
        Mockito.verify(mockDao).fetch(testObj);
    }
}

方式B:直接模拟CacheService

如果不需要关心CacheService的内部逻辑,直接模拟它的行为:

@ExtendWith(MockitoExtension.class)
class TransformerTest {
    @Mock
    private CacheService mockCacheService;
    private Transformer transformer;

    @BeforeEach
    void setUp() {
        transformer = new Transformer(mockCacheService);
    }

    @Test
    void doAction_ShouldCallCacheService() {
        CustomObject testObj = new CustomObject();
        transformer.doAction(testObj);
        
        Mockito.verify(mockCacheService).doAction(testObj); // 注意统一方法名
    }
}

方案3:改造CacheService为构造注入(推荐最佳实践)

字段注入(@Autowired标注在字段上)不利于测试和依赖管理,改成构造注入后,测试时可以手动传入依赖,无需反射:

@Component
public class CacheService {
    private final GenericBean genericBean;
    private final Dao dao;

    // Spring会自动装配构造方法的参数
    public CacheService(GenericBean genericBean, Dao dao) {
        this.genericBean = genericBean;
        this.dao = dao;
    }

    public void doAction(CustomObject o){
        dao.fetch(o);
    }
}

对应的测试代码:

class TransformerTest {
    @Test
    void doAction_Test() {
        // 模拟依赖
        Dao mockDao = Mockito.mock(Dao.class);
        GenericBean mockGenericBean = Mockito.mock(GenericBean.class);
        
        // 手动组装依赖链
        CacheService cacheService = new CacheService(mockGenericBean, mockDao);
        Transformer transformer = new Transformer(cacheService);

        CustomObject testObj = new CustomObject();
        transformer.doAction(testObj);

        // 验证行为
        Mockito.verify(mockDao).fetch(testObj);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 17:15:43