Spring Controller单元测试无法自动装配所需Bean问题
解决Spring Controller单元测试中Mock服务注入为null的问题
嘿,这个问题我太熟啦!你之所以碰到myService为null的情况,核心原因就是你直接new出来的MyController实例,压根没和你Mock好的myService关联上,控制器里的@Autowired字段自然找不到依赖啦~
下面给你几种简单好用的解决方案,挑你顺手的来:
方案一:用Mockito的@InjectMocks自动注入(最推荐)
Mockito专门提供了@InjectMocks注解,能自动把所有用@Mock标注的对象,注入到目标类的对应字段里。修改你的测试代码就行:
@RunWith(MockitoJUnitRunner.class) public class TestManageDevices { private MockMvc mockMvc; @Mock MyService myService; @InjectMocks // 关键:让Mockito自动把mock的myService注入到这个控制器实例 private MyController myController; @Before public void setUp() { // 用注入好依赖的myController来构建MockMvc mockMvc = MockMvcBuilders.standaloneSetup(myController) .build(); } // 你的测试方法保持不变... }
这个注解会自动匹配字段类型或名称,不管你控制器里用的是@Autowired、@Resource还是构造注入,都能搞定。
方案二:手动注入依赖(适合不想用注解的场景)
如果你不想用@InjectMocks,也可以手动给控制器的服务字段赋值:
- 如果你的
MyController有setMyService方法,直接调用就行:
@Before public void setUp() { MyController myController = new MyController(); myController.setMyService(myService); // 手动把mock的服务塞进去 mockMvc = MockMvcBuilders.standaloneSetup(myController) .build(); }
- 如果没有setter,也可以用反射硬塞(应急用,不推荐长期这么干):
@Before public void setUp() throws NoSuchFieldException, IllegalAccessException { MyController myController = new MyController(); Field serviceField = MyController.class.getDeclaredField("myService"); serviceField.setAccessible(true); // 突破私有字段限制 serviceField.set(myController, myService); mockMvc = MockMvcBuilders.standaloneSetup(myController) .build(); }
方案三:用Spring Boot Test的@WebMvcTest(适合Spring Boot项目)
如果你的项目是Spring Boot,也可以用@WebMvcTest注解,让Spring帮你管理上下文和依赖注入:
@WebMvcTest(MyController.class) public class TestManageDevices { @Autowired private MockMvc mockMvc; @MockBean // 把MyService的Mock实例注册到Spring上下文 private MyService myService; @Test public void shouldPass() throws Exception { // 测试逻辑完全不变... } }
这种方式更贴近真实运行环境,Spring会自动处理控制器的依赖,你甚至不用手动构建MockMvc。
最后提个小建议
现在更推荐用构造注入代替字段注入(就是在控制器的构造方法里接收MyService,而不是用@Autowired标注字段),这样不仅能避免null问题,还能让代码更易测试、更符合依赖注入的原则哦~
内容的提问来源于stack exchange,提问作者Ravat Tailor
相关产品推荐
相关产品推荐

