wiki:demo_06

单元测试应用示例——测试Filter

游戏大厅中的AdminAuthFilter,用来检验用户有没有防问被保护的jsp权限,代码如下

@Override
        public void doFilter(ServletRequest req, ServletResponse resp,
                        FilterChain chain) throws ServletException, IOException {
                
                HttpServletRequest request = (HttpServletRequest)req;
                HttpServletResponse response = (HttpServletResponse)resp;
                
                //请求路径
                String requestURI = request.getRequestURI();
                
                EnvInterface env = (EnvInterface) req.getAttribute("env");
                
                if(env.getUserInfo().getId() <= 0){
                        log.info("非法访问:"+requestURI);
                        response.sendRedirect(env.getRoot()+"/admin/login.jsp");
                        return;
                }else{
                        if(Pattern.matches(".+/admin/game/action/.+", requestURI)){
                                //管理员才有权限访问该目录下的资源
                                if(!env.isAdmin()){
                                        log.info("无权限访问:"+request.getRequestURI());
                                        response.sendRedirect(env.getRoot()+"/admin/login.jsp");
                                }else{
                                        chain.doFilter(req, resp);
                                }
                        }else{
                                chain.doFilter(req, resp);
                        }
                }
        }

filter依赖HttpServletRequest,HttpServletResponse?,FilterChain等对象,比较难测试,我们可以通过使用Spring测试框架提供的模拟对象,来辅助我们使用junit来测试。我们看到该doFilter方法中还依赖
Env对象,该对象非常复杂,非常难模拟。我们的测试似乎很难进行了,但我们如果使用了jMock的话,也能解决模拟Env对象,jMock模拟一个对象时,要求该对象必须实现某个接口,然后模拟该接口。
而Env对象并未实现任何接口,为了编写单元测试,我们让Env去实现EnvInterface接口

 /**
 * 
 * @author ChenYang
 * Date: 2012-1-10
 */
public interface EnvInterface {
        
        public User getUser();
        
        public UserInfo getUserInfo();
        
        public String getRoot();
        
        public boolean isAdmin();
}

Env实现EnvInterface 接口

public class Env implements EnvInterface{
 ..................
}

这次我们不选择Spring测试框架的提供Web模拟对象,改用jmock去模拟Web对象

        /**
         * 测试用户没有登陆
         * @throws Exception
         */
        @Test
        public void doFilter() throws Exception {
                
                Mockery ctx = new Mockery();

                //jMock模拟HttpServletRequest 
                final HttpServletRequest request = ctx.mock(HttpServletRequest.class);

                //jMock模拟HttpServletResponse 
                final HttpServletResponse response = ctx.mock(HttpServletResponse.class);

                //jMock模拟FilterChain 
                final FilterChain chain = ctx.mock(FilterChain.class);
                
                //jMock模拟chain 
                final EnvInterface env = ctx.mock(EnvInterface.class);
                
                final UserInfo user = new UserInfo();
                
                ctx.checking(new Expectations(){
                        {
                                //期望request.getAttribute("env");会调用一次,并返回env
                                one(request).getAttribute("env");
                                will(returnValue(env));
                                
                                 //期望request.getRequestURI();会调用一次,并返回"http://g2.pcgames.com.cn/admin/game/game.jsp"
                                one(request).getRequestURI();
                                will(returnValue("http://g2.pcgames.com.cn/admin/game/game.jsp"));
                                
                                  //期望env.getUserInfo();会调用一次,并返回user
                                one(env).getUserInfo();
                                will(returnValue(user));
                                
                                //期望env.getRoot();会调用一次,并返回"http://g2.pcgames.com.cn"
                                one(env).getRoot();
                                will(returnValue("http://g2.pcgames.com.cn"));
                                
                                //期望response.sendRedirect("http://g2.pcgames.com.cn/admin/login.jsp");会调用一次
                                one(response).sendRedirect("http://g2.pcgames.com.cn/admin/login.jsp");
                        }
                });
                
                AdminAuthFilter filter = new AdminAuthFilter();
                filter.doFilter(request, response, chain);
                
        }