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

不使用@InjectMocks时单元测试依赖注入空指针问题排查

问题根源

你直接通过new PageModelBuilder()实例化被测类,但@Inject注解是依赖注入框架(如Spring、CDI)或Mockito的@InjectMocks才会处理的标记,JVM手动实例化对象时只会初始化成员变量的默认值(引用类型为null),不会自动注入stringTranslator,所以才会出现空指针异常。

解决方法(无需修改被测类)

方法一:使用Mockito的@InjectMocks(推荐)

Mockito的@InjectMocks会自动将你标记为@Mock的依赖注入到被测类实例中,无需手动实例化和设置。修改测试类如下:

@RunWith(MockitoJUnitRunner.Silent.class)
public class PageModelBuilderTest {
    @Mock
    private StringTranslator stringTranslator;
    @InjectMocks // 自动注入mock依赖
    private PageModelBuilder pageModelBuilder;

    @Before
    public void setup() {
        if (!AppConfig.isInitialized()) {
            AppConfig.initialize("WebApp", null, new String[] {
                    "--root=.", "--domain=test"});
        }
    }

    @After
    public void after() {
        if (AppConfig.isInitialized()) {
            AppConfig.destroy();
        }
    }

    @Test
    public void givenProductDataWithProductLink_whenBuildPageModel_thenPageModelHasCanonicalURL() {
        AppConfig.insertString("baseUrl", "https://www.google.com");
        when(stringTranslator.getStringById("page_description_format")).thenReturn("sample description");
        
        ProductData productData = ProductTestData.getProductDataBuilder()
                .title("TestMed")
                .productLink("/PRODUCT-DESCRIPTION/dp/asin")
                .build();
        PageModel pageModel = pageModelBuilder.buildFrom(productData);
        
        assertEquals("https://www.google.com/PRODUCT-DESCRIPTION/dp/asin", pageModel.getCanonicalURL());
        // 可选:验证mock对象的调用逻辑
        verify(stringTranslator).getStringById("page_description_format");
    }
}

方法二:反射手动注入(适合无法使用@InjectMocks的场景)

如果必须手动实例化被测类,可以通过Java反射绕过访问权限,将mock的stringTranslator设置到私有成员变量中:

在测试方法中实例化pageModelBuilder后添加以下代码:

pageModelBuilder = new PageModelBuilder();
// 反射获取私有成员并注入mock
Field translatorField = PageModelBuilder.class.getDeclaredField("stringTranslator");
translatorField.setAccessible(true); // 开启私有字段访问权限
translatorField.set(pageModelBuilder, stringTranslator); // 注入mock对象
注意事项
  • 方法一基于Mockito原生机制,代码简洁易维护,是单元测试中依赖注入的标准做法。
  • 方法二依赖反射,代码繁琐且容易因类结构变更失效,仅作为备选方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 00:10:43