开始学习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会搭配使用。
浙公网安备 33010602011771号