Zacard's Notes

单元测试中涉及到mybatis plugin时需要注意的地方

背景

当编写test case的时候,如果测试内容中又涉及到mybatis plugin(interceptor)的时候,可能会出现奇怪的问题。比如一部分mybatis的dao调用进入了plugin,一小部分却不经过plugin。

例子

请看如下单元测试代码:

/**
 * 测试分页查询
 */
@Test
public void testQueryPage() {
    // 分页对象
    Pager<Account> pager = new Pager<>();
    pager.setCurrentPage(2);
    pager.setPageSize(10);
    // 查询参数
    QueryParams queryParams = new QueryParams();
    queryParams.setRole("ADMIN");
    // 调用查询接口
    List<Account> accounts1 = accountDAO.queryPage(queryParams, pager);
    Assert.assertTrue(accounts1.size() == 1);
    // 调用查询接口
    pager.setCurrentPage(1);
    List<Account> accounts2 = accountDAO.queryPage(queryParams, pager);
    Assert.assertTrue(accounts2.size() == 10);
}

mybatis plugin代码:

/**
 * <p>
 * 数据库分页和排序插件,只拦截查询语句.
 * </p>
 *
 */
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class})})
public class QueryInterceptor implements Interceptor{
    ...
}

这时候,跑测试类,第二次调用dao接口的时候,没有进入mybatis的plugin,断言也是不通过的。这是由于mybatis的一级缓存的机制。

原因

当几个查询出于同一个sqlsession查询的时候,并且mybatis认为是完全相同的查询,mybatis是使用一级缓存的结果,而不会走拦截StatementHandler接口的插件方法。(mybatis认为的完全相同的查询,不是指使用sqlsession查询时传递给算起来session的所有参数值完完全全相同,你只要保证statementId,rowBounds,最后生成的SQL语句,以及这个SQL语句所需要的参数完全一致就可以了。

总结

这个问题教育我们,test case的方法要尽量独立,测试用例尽量测试一个业务或者逻辑。

Ps:mybatis一级缓存机制参考这里;mybatis拦截器参考这里

坚持原创技术分享,您的支持将鼓励我继续创作!

热评文章