背景
当编写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的方法要尽量独立,测试用例尽量测试一个业务或者逻辑。