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

Mockito模拟LDAPConnectionPool时总是调用父类真实方法问题

Mockito模拟LDAPConnectionPool.search返回null的问题解决

问题场景

尝试用Mockito模拟LDAPConnectionPool的search方法生成测试数据,但实际调用时始终返回null,断点验证发现真实方法被执行。排查数小时后怀疑和抽象父类有关,但无法修改这些类,调试难度较高。

依赖环境

使用的Mockito相关Maven依赖:

<artifactId>mockito-junit-jupiter</artifactId>
<version>5.4.0</version>
<artifactId>mockito-core</artifactId>
<version>5.4.0</version>
<artifactId>mockito-inline</artifactId>
<version>5.2.0</version>

调用日志

方法调用日志显示传入的第一个参数为null,返回结果为null:

############ Logging method invocation #2 on mock/spy ########
ldapConnectionPool.search(
    null,
    SUB,
    "(mail=a@b.c)"
);
    invoked: -> at package.Class.method(Class.java:228)
    has returned: "null"

相关类定义

  • 被模拟类:
package com.unboundid.ldap.sdk;
public final class LDAPConnectionPool
       extends AbstractConnectionPool
  • 父类真实方法:
public final SearchResult search(final String baseDN, final SearchScope scope,
                               final String filter,
                               final String... attributes)
     throws LDAPSearchException
{
  return search(new SearchRequest(baseDN, scope, parseFilter(filter),
       attributes));
}

初始测试代码

最初的测试代码中,使用带类型限制的匹配器设置模拟返回:

@ExtendWith(SpringExtension.class)
class ClassTest {

    @MockBean
    private LdapConnectionPoolProvider ldapConnectionPoolProvider;

    private LDAPConnectionPool ldapConnectionPool= mock(LDAPConnectionPool.class, withSettings().verboseLogging());;

    private AutoCloseable closeable;

    @BeforeEach
    void beforeTest() {
        closeable= MockitoAnnotations.openMocks(this);
    }

    @AfterEach
    void afterTest() throws Exception {
        closeable.close();
    }

    @Test
    void methodSuccess() throws LDAPSearchException {

        SearchResult res = new SearchResult(1243, ResultCode.SUCCESS, "", "", null, searchEntries, null, 0, 0, null);
        // 此处匹配器设置导致模拟失效
        doReturn(res).when(ldapConnectionPool).search(any(String.class), any(SearchScope.class), any(String.class));

        SearchResult result = ldapConnectionPool.search(getBaseDN(), SearchScope.SUB, "(mail=" + getMail() + ")");
    }
}

问题复现与解决方法

通过复现案例验证,发现问题出在参数匹配器的使用上:

复现测试代码

@Slf4j
public class Tester {
    private LDAPConnectionPool ldapConnectionPool = mock(LDAPConnectionPool.class, withSettings().verboseLogging());

    private AutoCloseable closeable;
    @Mock
    private LdapAIOConnection ldapAIOConnection;

    @BeforeEach
    void init() {
        log.info("@BeforeEach - executes before each test method in this class");
    }

    @BeforeEach
    void beforeTest() {
        closeable = MockitoAnnotations.openMocks(this);
        doReturn(ldapConnectionPool).when(ldapAIOConnection).ldapConnectionPool();
    }

    @AfterEach
    void afterTest() throws Exception {
        closeable.close();
    }

    @Test
    void testIt() throws LDAPSearchException {
        List<SearchResultEntry> searchEntries = new ArrayList<>();
        String GUID = "??";
        String accControlCode = "512";
        String lastPassSet = "1234";

        Collection<Attribute> attrs = new HashSet<>(Arrays.asList(new Attribute("objectGUID", GUID),
            new Attribute("pwdLastSet", lastPassSet), new Attribute("userAccountControl", accControlCode)));
        searchEntries.add(new SearchResultEntry("", attrs, new Control("12")));

        SearchResult res = new SearchResult(1243, ResultCode.SUCCESS, "a.a.c", "a/a/a", null, searchEntries, null, 1, 1, null);
        
        // 写法1:模拟失效,返回null
        // doReturn(res).when(ldapConnectionPool).search(any(String.class), any(SearchScope.class), any(String.class));

        // 写法2:模拟成功,返回预期结果
        doReturn(res).when(ldapConnectionPool).search(any(), any(SearchScope.class), any(String.class));

        SearchResult result = ldapConnectionPool.search(null, SearchScope.SUB, "");
        Assertions.assertEquals(1, result.getEntryCount());
    }
}

解决方法

将第一个参数的匹配器从any(String.class)改为无类型限制的any(),即可让Mockito正确匹配方法调用并返回模拟结果。

原因分析:当传入的参数为null时,any(String.class)无法匹配null值(因为null不属于任何类型的实例),而无类型的any()可以匹配包括null在内的任意参数,因此能正确触发模拟逻辑。


内容的提问来源于stack exchange,提问作者Martin P.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 17:37:31