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

不使用PowerMock,Mock无返回值方法中的JdbcTemplate实例创建

可行解决方案:重构代码解耦依赖创建逻辑

Mockito本身无法直接拦截new关键字创建对象的行为,核心思路是把JdbcTemplate的创建逻辑从setDataSource方法中抽离出来,让这部分逻辑可替换、可Mock。

方法1:抽离工厂方法(推荐)

修改BaseDao类,新增一个protected的工厂方法负责创建JdbcTemplate,测试时通过子类重写该方法返回Mock对象:

修改后的BaseDao代码

public class BaseDao {
    protected JdbcTemplate defaultTemplate;

    protected void setDataSource(DataSource dataSource) {
        this.defaultTemplate = createJdbcTemplate(dataSource);
    }

    // 抽离的工厂方法,供测试子类重写
    protected JdbcTemplate createJdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

对应的测试代码

@ExtendWith(MockitoExtension.class)
public class BaseDaoTest {
    
    @Mock
    private JdbcTemplate mockedDefaultTemplate;
    @Mock
    private DataSource mockDataSource;

    @Test
    public void testSetDataSource() {
        // 创建BaseDao的匿名子类,重写工厂方法返回Mock对象
        BaseDao testDao = new BaseDao() {
            @Override
            protected JdbcTemplate createJdbcTemplate(DataSource dataSource) {
                // 验证传入的数据源是预设的Mock对象
                assertSame(mockDataSource, dataSource);
                return mockedDefaultTemplate;
            }
        };

        testDao.setDataSource(mockDataSource);
        // 验证defaultTemplate确实是我们的Mock对象
        assertSame(mockedDefaultTemplate, testDao.defaultTemplate);
    }
}

方法2:依赖注入JdbcTemplate(更符合DI原则)

如果允许调整原有设计,直接将JdbcTemplate作为依赖注入到BaseDao中,而非在setDataSource内创建,测试时直接注入Mock对象即可:

修改后的BaseDao代码

public class BaseDao {
    protected JdbcTemplate defaultTemplate;

    // 提供Setter注入入口
    public void setDefaultTemplate(JdbcTemplate defaultTemplate) {
        this.defaultTemplate = defaultTemplate;
    }

    // 保留setDataSource方法,改为更新模板的数据源
    protected void setDataSource(DataSource dataSource) {
        this.defaultTemplate.setDataSource(dataSource);
    }
}

对应的测试代码

@ExtendWith(MockitoExtension.class)
public class BaseDaoTest {
    
    @Mock
    private JdbcTemplate mockedDefaultTemplate;
    @Mock
    private DataSource mockDataSource;

    @Test
    public void testSetDataSource() {
        BaseDao testDao = new BaseDao();
        testDao.setDefaultTemplate(mockedDefaultTemplate);

        testDao.setDataSource(mockDataSource);
        // 验证JdbcTemplate的setDataSource方法被正确调用
        verify(mockedDefaultTemplate).setDataSource(mockDataSource);
    }
}

补充说明

你提到的PowerMock虽能拦截new操作,但依赖字节码修改,与JUnit 5兼容性差,还会提升测试代码的耦合度,不利于长期维护。上面的重构方案更符合面向对象设计原则,同时让测试逻辑简洁可靠。

内容的提问来源于stack exchange,提问作者Plainsage

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 15:09:58