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

测试含Autowired对象的Spring服务类遇空指针,求正确测试方法

问题原因与解决方案

你的测试代码中,虽然Mock了ExternalService,但并没有将这个Mock对象注入到MyService实例中,导致MyService里的externalService字段始终为null,触发空指针异常。以下是几种正确的写法:

方案一:使用@InjectMocks自动注入(快速解决)

Mockito的@InjectMocks注解会自动将标记为@Mock的对象注入到目标实例中,修改测试类如下:

@ExtendWith(MockitoExtension.class)
public class MyServiceTest {
    // @Mock注解会自动创建ExternalService的Mock实例,无需手动调用Mockito.mock
    @Mock
    private ExternalService externalService;

    // @InjectMocks会将上面的Mock对象注入到MyService实例中
    @InjectMocks
    private MyService myService;

    @Test
    public void methodToTest_Test() {
        // 注意:thenReturn不能用匹配器anyString(),要返回具体值
        Mockito.when(externalService.call(Mockito.anyString())).thenReturn("模拟的响应内容");
        
        // 调用待测试方法
        String result = myService.methodToTest("测试参数");
        
        // 验证ExternalService的call方法是否被调用
        Mockito.verify(externalService).call("测试参数");
        
        // 这里可以添加断言验证结果
        // Assertions.assertEquals("预期返回值", result);
    }
}

方案二:改用构造器注入(推荐的最佳实践)

Spring官方推荐使用构造器注入依赖,这种方式不仅让依赖关系更清晰,也能避免测试时的注入问题。先修改MyService:

@Service
public class MyService {
    // 用final修饰确保依赖不可变
    private final ExternalService externalService;

    // 构造器注入,Spring 4.3+可以省略@Autowired注解
    public MyService(ExternalService externalService) {
        this.externalService = externalService;
    }

    public String methodToTest(String myArg) {
        String response = externalService.call(myArg);
        // ...业务逻辑
        return response;
    }
}

然后测试类可以直接手动传入Mock对象,无需依赖@InjectMocks:

@ExtendWith(MockitoExtension.class)
public class MyServiceTest {
    @Mock
    private ExternalService externalService;

    private MyService myService;

    // 每个测试前初始化MyService实例
    @BeforeEach
    void setUp() {
        myService = new MyService(externalService);
    }

    @Test
    public void methodToTest_Test() {
        Mockito.when(externalService.call("测试参数")).thenReturn("模拟响应");
        
        String result = myService.methodToTest("测试参数");
        
        Mockito.verify(externalService).call("测试参数");
        // Assertions.assertEquals("模拟响应", result);
    }
}

原代码的其他问题说明

  • 使用@Mock注解时,不需要手动调用Mockito.mock(ExternalService.class),注解会自动完成Mock实例的创建。
  • thenReturn(anyString())是错误用法:anyString()是参数匹配器,只能用于方法参数位置,返回值需要传入具体的字符串。

内容的提问来源于stack exchange,提问作者Lorenzo D'Isidoro

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 23:40:22