Mockito测试失败:期望sshMap.put调用未触发,求解决方案
问题解决方案
错误原因解析
- Mock对象未关联业务类:测试中创建的
sshMapMock实例没有注入到WebSshServiceImpl中,业务代码实际使用的是自身内部的sshMap,导致Mock从未被调用,触发verify失败。 - Session属性未正确Mock:直接调用
session.getAttributes().put()会触发空指针,因为Mock的session默认返回null,需要先MockgetAttributes()返回可用Map。 - 参数匹配逻辑错误:测试中手动创建的
SshConnectInfo和业务代码内部生成的不是同一个实例,直接用该实例匹配verify会失败。 - 不必要的Stub操作:用
doReturn(...)Stubput方法完全多余,测试目标是验证方法调用,而非控制返回值。
修改步骤
1. 调整业务类,支持依赖注入
修改WebSshServiceImpl,通过构造函数传入sshMap,方便测试时注入Mock对象:
@Service public class WebSshServiceImpl implements WebSshService { private final ConcurrentMap<String, Object> sshMap; // 构造函数注入sshMap,兼容Spring环境和测试 public WebSshServiceImpl(int someParam, ConcurrentMap<String, Object> sshMap) { // 原有的业务参数处理逻辑 this.sshMap = sshMap; } @Override public void initConnection(WebSocketSession session) { JSch jSch = new JSch(); SshConnectInfo sshConnectInfo = new SshConnectInfo(); sshConnectInfo.setJSch(jSch); sshConnectInfo.setWebSocketSession(session); String uuid = String.valueOf(session.getAttributes().get(ConstantPool.USER_UUID_KEY)); sshMap.put(uuid, sshConnectInfo); } }
2. 修正测试代码
public class WebSshServiceImplTest { private WebSshServiceImpl webSshService; @Mock private ConcurrentMap<String, Object> sshMap; // 仅用@Mock创建Mock实例,无需手动new @Mock private WebSocketSession session; @Mock private Map<String, Object> sessionAttributes; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); // 将Mock的sshMap传入业务类实例 this.webSshService = new WebSshServiceImpl(20, sshMap); // Mock Session的属性返回值 when(session.getAttributes()).thenReturn(sessionAttributes); when(sessionAttributes.get(ConstantPool.USER_UUID_KEY)).thenReturn("asdfgh"); } @Test public void initConnectionSuccess() throws Exception { webSshService.initConnection(session); // 验证put方法被调用,用参数匹配器处理内部实例的匹配 verify(sshMap, times(1)).put(eq("asdfgh"), any(SshConnectInfo.class)); // 可选:验证SshConnectInfo的属性正确性 verify(sshMap, times(1)).put(eq("asdfgh"), argThat(info -> info.getWebSocketSession() == session && info.getJSch() != null )); } }
3. 解决Autowired注入空指针问题
如果要在测试中用@Autowired注入服务,需启动Spring上下文并替换Mock对象:
@SpringBootTest public class WebSshServiceImplTest { @Autowired private WebSshServiceImpl webSshService; @MockBean // 替换Spring容器中的sshMap为Mock实例 private ConcurrentMap<String, Object> sshMap; @Mock private WebSocketSession session; @Mock private Map<String, Object> sessionAttributes; @Before public void setUp() throws Exception { when(session.getAttributes()).thenReturn(sessionAttributes); when(sessionAttributes.get(ConstantPool.USER_UUID_KEY)).thenReturn("asdfgh"); } @Test public void initConnectionSuccess() throws Exception { webSshService.initConnection(session); verify(sshMap, times(1)).put(eq("asdfgh"), any(SshConnectInfo.class)); } }
同时需确保sshMap在Spring容器中注册为Bean:
@Configuration public class SshConfig { @Bean public ConcurrentMap<String, Object> sshMap() { return new ConcurrentHashMap<>(); } }
内容的提问来源于stack exchange,提问作者kavya raj
相关产品推荐
相关产品推荐

