开始学习springside的内核代码, 主要学习目标:
1. 如何测试驱动开发
2. 如何rapid dev

 

JCaptchaFilterTest:
主要演示了各种ServletAPI的mock对象的使用.
先看初始化:
//从MockFilterConfig中获得一个ServletContext对象
MockServletContext context = (MockServletContext) config.getServletContext();

//WebTestUtils是springside中的测试工具,完成:
//1.Spring WebApplicationContext初始化到ServletContext.
//2.将MockRequest/MockResponse放入Struts2的ServletActionContext.
// 在ServletContext里初始化Spring WebApplicationContext.
WebTestUtils.initWebApplicationContext(context, "/applicationContext-extension-test-security.xml");
###                                                                  
// apache.commons的一个方便方法, 用于把数组用","连接
String configLocationsString = StringUtils.join(configLocations, ",");    
// servletContext 其实就是web.xml这个文件
// 这里面设的参数就是为了能在web程序启动的时候找到spring的配置文件
// 相当于web.xml中的
// <context-param>
//        <param-name>contextConfigLocation</param-name>
//        <param-value>classpath*:/applicationContext.xml,classpath*:/applicationContext-security.xml</param-value>
// </context-param>
servletContext.addInitParameter(ContextLoader.CONFIG_LOCATION_PARAM, configLocationsString);   
// 初始化servletContext 
new ContextLoader().initWebApplicationContext(servletContext);
###
// FilterConfig 接口就是把信息传递给过滤器的
// 设置过滤失败的url
config.addInitParameter(JCaptchaFilter.PARAM_FAILURE_URL, failUrl);  

测试图像显示:
public void displayImage() throws ServletException, IOException {    
        //非 FilterProcessesURL 均为图片生成URL.
        //设置request请求路径
        request.setServletPath("/img/capatcha.jpg");
   
    //初始化filter
        filter.init(config);
        filter.doFilter(request, response, chain);
   
    //返回状态为成功
        assertEquals(200, response.getStatus());
        //返回类型为image/jpeg
        assertEquals("image/jpeg", response.getContentType());    
        //返回内容大于0
        assertEquals(true, response.getContentAsByteArray().length > 0);
    }

测试验证失败:
public void validateWithErrorCaptcha() throws ServletException, IOException {     
        //设置默认的过滤器处理url
        request.setServletPath(JCaptchaFilter.DEFAULT_FILTER_PROCESSES_URL);  
        //设置参数
        request.setParameter(JCaptchaFilter.PARAM_CAPTCHA_PARAMTER_NAME, "12345678ABCDEFG");
   
    //初始化filter
        filter.init(config);
        filter.doFilter(request, response, chain);
   
        assertEquals(failUrl, response.getRedirectedUrl());
    }

这个测试就是这么简单, 反过来我们来看一下这个验证码过滤器: JCaptchaFilter
先看初始化过程:
if (StringUtils.isBlank(fConfig.getInitParameter(PARAM_FAILURE_URL)))
{           
// 如果缺少必要的参数, 直接抛出异常
            throw new IllegalArgumentException("CaptchaFilter缺少failureUrl参数");
}         
// 获取captchaService
// 这里面获取ApplicationContext使用的是spring的一个标准方法
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(fConfig.getServletContext());
captchaService = (CaptchaService) context.getBean(captchaServiceId);

看一下过滤器的逻辑:
public void doFilter(final ServletRequest theRequest,
            final ServletResponse theResponse, final FilterChain chain)
            throws IOException, ServletException
    {
        HttpServletRequest request = (HttpServletRequest) theRequest;
        HttpServletResponse response = (HttpServletResponse) theResponse;
        String servletPath = request.getServletPath();
       
        //符合filterProcessesUrl为验证处理请求,其余为生成验证图片请求.
        if (StringUtils.indexOf(servletPath, filterProcessesUrl) == 0)
        {
            boolean validated = validateCaptchaChallenge(request);
            if (validated)
            {
                chain.doFilter(request, response);
            }
            else
            {  
                    //返回到具体的一个url上
                response.sendRedirect(request.getContextPath() + failureUrl);
            }
        }
        else
        {
            genernateCaptchaImage(request, response);
        }
    }     
   
验证的代码很简单:
String captchaID = request.getSession().getId(); // 获取sessionid
String challengeResponse = request.getParameter(captchaParamterName); // 读取用户的输入
captchaService.validateResponseForID(captchaID,challengeResponse); // 验证

生成图片:   
// 设置禁止客户端缓存的Header.
ServletUtils.setDisableCacheHeader(response);
response.setContentType("image/jpeg");
ServletOutputStream out = response.getOutputStream();
String captchaId = request.getSession(true).getId();  //获取session id
BufferedImage challenge = (BufferedImage) captchaService.getChallengeForID(captchaId,request.getLocale());
ImageIO.write(challenge, "jpg", out);
out.flush();

CryptoUtilsTest:
这一部分代码主要是学习一下加密, 如何使用加密算法. 具体待后面的分析代码中解释.

VelocityUtilsTest:
主要测试如何使用Velocity模板生成内容.

 

QueueTest测试类: 
测试方法backup:
// 学习如何获取临时文件夹
String filePath = System.getProperty("java.io.tmpdir") + File.separator + "queue" + File.separator + queueName;
// 获取一个java.util 中的阻塞队列, 如果不存在, 则创建一个, 并放入一个ConcurrentMap中
BlockingQueue queue = QueuesHolder.getQueue(queueName);                  
// 向队列中插入一个对象
queue.offer(date1);       
// springside的这个单线程任务类, 任务开始的时候要从备份文件中恢复队列
// 任务结束的时候要把数据备份的到文件中
MockConsumerTask task = new MockConsumerTask();
task.setQueueName(queueName);
task.start();
task.stop();  

 

//接下来就是验证文件中对象个数是否正确
File file = new File(filePath);
  assertEquals(true, file.exists());

  ObjectInputStream oos = new ObjectInputStream(new FileInputStream(file));
  List list = new ArrayList();
  while (true) {
   try {
    Object obj = oos.readObject();
    list.add(obj);
   } catch (EOFException e) {
    break;
   }
  }
  oos.close();    
assertEquals(2, list.size());
assertEquals(date1, list.get(0)); 

MemcachedTest测试类:
// springside封装的测试类, 这个类主要是为了测试memcached用的
private static JmemcachedServer server = new JmemcachedServer();
//演示了封装好的客户端如何保存和取出对象值    
//spyClientFactory应该是一个客户端工厂类, 之后应该自己分析一下实现的细节
spyClientFactory.getClient().set(key, 60 * 60 * 1, value);
String result = spyClient.get(key);
assertEquals(value, result);

值得注意的是:
除了MemcachedTest测试类之外, 其他的测试类都继承了Assert类, 因为这些类都没有使用spring的配置文件,如果使用配置文件的话,
推荐使用springside封装好的测试基类:
@DirtiesContext
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners( { DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class })
public abstract class SpringContextTestCase extends Assert implements ApplicationContextAware {

 protected Logger logger = LoggerFactory.getLogger(getClass());

 protected ApplicationContext applicationContext;

 public final void setApplicationContext(final ApplicationContext applicationContext) {
  this.applicationContext = applicationContext;
 }

主要是实现了ApplicationContextAware接口
Spring中提供一些Aware相关接口,像是BeanFactoryAware、 ApplicationContextAware、ResourceLoaderAware、ServletContextAware等,
实作这些 Aware接口的Bean在被初始之后,可以取得一些相对应的资源,
例如实作BeanFactoryAware的Bean在初始后,Spring容器将会注入BeanFactory的实例,
而实作ApplicationContextAware的Bean,在Bean被初始后,将会被注入 ApplicationContext的实例

至于这3个annotation, 参考annotation的文章 
@DirtiesContext
在测试方法上出现这个注解时,表明底层Spring容器在该方法的执行中被“污染”,从而必须在方法执行结束后重新创建(无论该测试是否通过)。
@RunWith(SpringJUnit4ClassRunner.class)
在使用所有注释前必须使用@RunWith(SpringJUnit4ClassRunner.class),让测试运行于Spring测试环境
@TestExecutionListeners( { DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class })
定义类级别的元数据,TestExecutionListeners会使用TestContextManager进行注册。
通常,@TestExecutionListeners与@ContextConfiguration会搭配使用。   

 

 

posted on 2010-12-09 13:31  菊次郎  阅读(369)  评论(0)    收藏  举报