Apache Shiro单元测试:checkPermission无视存根权限仍通过
这个问题我刚接触Mockito的时候也踩过一模一样的坑!核心原因是Mockito模拟出来的对象,每个方法都是独立的,不会自动继承真实类里的方法调用逻辑。
你存根了isPermitted("review:edit:regional")返回false,但这只对直接调用isPermitted有效。而checkPermission方法在模拟的Subject里,默认是啥都不做的空实现——它不会像真实的Shiro Subject那样,内部调用isPermitted并在返回false时抛出AuthorizationException。
两种可行的解决方案:
方案1:直接存根checkPermission方法抛出异常
既然你的测试场景是要验证调用checkPermission("review:edit:regional")时会触发权限异常,最直接的方式就是直接给这个方法的调用存根抛出异常:
// 注意这里要用doThrow语法,因为checkPermission是void方法 doThrow(new AuthorizationException()) .when(subject) .checkPermission("review:edit:regional");
这样当你的静态类调用subject.checkPermission("review:edit:regional")时,就会抛出预期的异常,测试就能正常通过了。
方案2:让checkPermission关联isPermitted的存根逻辑
如果你希望模拟更贴近真实Subject的行为(比如所有权限校验都遵循isPermitted的结果),可以用thenAnswer来让checkPermission方法根据isPermitted的返回值决定是否抛异常:
// 先存根isPermitted的逻辑 when(subject.isPermitted("review:edit:regional")).thenReturn(false); // 再让checkPermission调用isPermitted并处理结果 when(subject.checkPermission(anyString())).thenAnswer(invocation -> { String permission = invocation.getArgument(0); if (!subject.isPermitted(permission)) { throw new AuthorizationException("权限不足"); } return null; // checkPermission是void方法,返回null即可 });
这种方式适合需要批量处理多个权限校验场景的测试,不用逐个存根checkPermission。
补充说明
你测试isPermitted时符合预期,是因为你直接给这个方法设置了返回值,Mockito会严格按照你存根的逻辑返回。而checkPermission作为void方法,Mockito默认不会执行任何操作,也不会自动关联其他方法的存根,所以才会出现你看到的现象。
内容的提问来源于stack exchange,提问作者Stego

