SpringBoot JUnit中Mock Firebase TopicManagementResponse遇null问题排查
Mock TopicManagementResponse 空值问题排查与解决
问题描述
使用Mockito.mock(TopicManagementResponse.class)Mock对象后,测试时仍提示response为空,需确认该Mock方式是否正确,以及可行的解决方法,目标是借助该对象完成Controller方法的测试。
相关代码
Controller类代码
@PostMapping("/subscribeToTopic") public int createTopic(@RequestBody Topic topic) throws IOException, FirebaseMessagingException { String platformID = topic.getPlatformId(); // 内部方法获取firebase messaging实例 FirebaseMessaging firebaseMessaging = fcmInitializer.getFirebaseMessaging(platformID); // 从JSON的"topic"字段获取主题名 String topicName = topic.getTopicName(); // 校验主题名非空 if (topicName == null || topicName.isEmpty()) { return 0; } TopicManagementResponse response = firebaseMessaging.subscribeToTopic(topic.getToken(), topicName); return response.getSuccessCount(); }
原测试类代码
public void createTopic(){ FirebaseMessaging firebaseMessaging = mock(FirebaseMessaging.class); TopicManagementResponse response = mock(TopicManagementResponse.class); Topic topic = new Topic(); topic.setToken("some token"); topic.setTopic("some topic"); when(firebaseMessaging.subscribeToTopic(topic.getToken(), topic.getTopic())).thenReturn(response); assertEquals(response.getSuccessCount, 1); }
问题原因分析
- Mock实例未注入Controller:Controller中使用的
FirebaseMessaging是通过fcmInitializer.getFirebaseMessaging()获取的,而非测试中Mock的实例,导致subscribeToTopic不会返回预设的response,实际拿到null。 - 字段不匹配导致参数校验失败:Controller中使用
topic.getTopicName()获取主题名,但测试中调用topic.setTopic("some topic"),字段名不匹配,Mock的方法调用无法触发。 - 未预设Mock对象的方法返回值:即使拿到
TopicManagementResponse的Mock实例,未预设getSuccessCount()的返回值,调用时会返回对应类型的默认值(int类型默认0)。 - 测试方法缺少注解:未添加
@Test注解(JUnit环境下),测试逻辑不会被执行。
修正后的测试方案
步骤1:确保Controller依赖可注入
确保Controller中的fcmInitializer通过依赖注入方式引入,比如:
@RestController public class TopicController { @Autowired private FcmInitializer fcmInitializer; // 原createTopic方法... }
步骤2:编写修正后的测试类
import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) public class TopicControllerTest { @Mock private FcmInitializer fcmInitializer; // Mock Controller依赖的初始化类 @Mock private FirebaseMessaging firebaseMessaging; // Mock FirebaseMessaging实例 @Mock private TopicManagementResponse topicManagementResponse; // Mock返回对象 @InjectMocks private TopicController topicController; // 注入Mock对象到Controller @Test public void createTopic_ShouldReturnSuccessCount() throws IOException, FirebaseMessagingException { // 构造测试用的Topic对象,确保字段匹配 Topic topic = new Topic(); topic.setToken("some token"); topic.setTopicName("some topic"); // 对应Controller中的getTopicName() topic.setPlatformId("test-platform"); // 预设fcmInitializer返回Mock的FirebaseMessaging when(fcmInitializer.getFirebaseMessaging(topic.getPlatformId())).thenReturn(firebaseMessaging); // 预设subscribeToTopic方法返回Mock的response when(firebaseMessaging.subscribeToTopic(topic.getToken(), topic.getTopicName())) .thenReturn(topicManagementResponse); // 预设response的getSuccessCount返回1 when(topicManagementResponse.getSuccessCount()).thenReturn(1); // 调用Controller方法 int result = topicController.createTopic(topic); // 断言返回值符合预期 assertEquals(1, result); } }
其他可行Mock方式
如果不想使用@Mock注解,也可以手动创建Mock实例并注入:
public void createTopic_ManualMock() throws IOException, FirebaseMessagingException { FcmInitializer mockInitializer = mock(FcmInitializer.class); FirebaseMessaging mockFcm = mock(FirebaseMessaging.class); TopicManagementResponse mockResponse = mock(TopicManagementResponse.class); TopicController controller = new TopicController(); // 通过setter或者反射注入mockInitializer到controller when(mockInitializer.getFirebaseMessaging("test-platform")).thenReturn(mockFcm); when(mockFcm.subscribeToTopic("some token", "some topic")).thenReturn(mockResponse); when(mockResponse.getSuccessCount()).thenReturn(1); Topic topic = new Topic(); topic.setToken("some token"); topic.setTopicName("some topic"); topic.setPlatformId("test-platform"); assertEquals(1, controller.createTopic(topic)); }
内容的提问来源于stack exchange,提问作者akashi paul
相关产品推荐
相关产品推荐

