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

Mockito测试失败:期望sshMap.put调用未触发,求解决方案

问题解决方案

错误原因解析

  1. Mock对象未关联业务类:测试中创建的sshMap Mock实例没有注入到WebSshServiceImpl中,业务代码实际使用的是自身内部的sshMap,导致Mock从未被调用,触发verify失败。
  2. Session属性未正确Mock:直接调用session.getAttributes().put()会触发空指针,因为Mock的session默认返回null,需要先MockgetAttributes()返回可用Map。
  3. 参数匹配逻辑错误:测试中手动创建的SshConnectInfo和业务代码内部生成的不是同一个实例,直接用该实例匹配verify会失败。
  4. 不必要的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 10:12:55