使用 Selenium 进行 Web 程序 验收测试

 Web 程序测试是一项十分繁杂的工作,要面对无数的分支,整个过程十分枯燥,既浪费时间,又容易出错。

要是有一个自动化的测试程序就好了。

Selenium 就是这样一个基于浏览器的验收测试程序。

官方网站:http://www.openqa.org/selenium/

点击下载 selenium-ide-0.8.7.xpi

这里有演示视频:Selenium_IDE.swf  。

Selenium is a test tool for web applications. Selenium tests run directly in a browser, just as real users do. And they run in Internet Explorer, Mozilla and Firefox on Windows, Linux, and Macintosh. No other test tool covers such a wide array of platforms.

  • Browser compatibility testing. Test your application to see if it works correctly on different browsers and operating systems. The same script can run on any Selenium platform.
  • System functional testing. Create regression tests to verify application functionality and user acceptance.

Internet Explorer无法打开站点,已终止操作 解决方案

关键词:IE, JavaScript, AJAX, “Internet Explorer无法打开站点,已终止操作”

错误原因:在页面还没有 ready 的时候就调用了 htmlObject 的 appendChild 或者 innerHTML 操作。

解决方案:在 appendChild 或者 innerHTML 操作处判断
document.readyState==”complete”
若为否,则 setTimeout 若干秒之后重新作这个操作。

readyState 有 complete,interactive 等值,具体可参考 Ajax Hacks 这本书,里面对不同浏览器关于此属性的不同取值有详细的说明。

另,IE 浏览器总是存在各种奇怪的问题,有时,只要在适当的地方加入 setTimeout 即可解决。具体是什么原因还没搞明白,只知道这种办法确实有效!

再此感谢 Lqx 同学提供的帮助。

变形金刚电影下载 RMVB FTP 上集 + 下集

现在各大影院票都卖完了,为了照顾没有看到电影的朋友,我这里提供了电影文件下载。

不是 BT 种子!!

是 RMVB 文件下载,只要安装 “暴风影音” 即可播放!

由于服务器压力很大,而且盗链情况严重,导致网站无法打开。

我连夜做了一个限制 IP 的程序,每个 IP 只能开 1 个线程下载。

由于限 IP 的程序开发时间比较紧,迅雷有时候会无法下载,我研究了一下,跟迅雷频繁断开连接又重新打开连接有关 ,因此,建议用 flashget 等下载工具,开单线程下载,否则 IP 将进入黑名单列表!

另,用 IE 或 Firefox 单线程下载也没问题,Firefox 的下载很好用,支持端点续传,只要用邮件点击下述链接,选择”另存为”即可。如果下载失败,请稍候 1 分钟,重试即可。

上集:

Transformers_CD1.rmvb

下集:

Transformers_CD2.rmvb

Smarty 定界符 花括号 大括号 函数定义 转义

使用 Smarty 模板的时候,通常都是用 ‘{‘ 和 ‘}’ 作为定界符(delimiter)。

有时,我们需要在 html 代码里输出大括号,如果在模板里直接写出来,会被 Smarty 的解析器认为是定界符,然后会报错:

Smarty error : syntax error: unrecognized tag

无法识别的标签!

如何解决呢?有 2 种办法:

1:内置变量

ldelim, rdelim
ldelim and rdelim are used for displaying the literal delimiter, in our case “{” or “}”. The template engine always tries to interpret delimiters, so this is the way around that.

ldelim 和 rdelim 用于输出分隔符,也就是大括号 ‘{‘ 和 ‘}’。如果只是输出很少的几个大括号,请使用此方法。

2: 文本转义

我们经常会在 html 里写 javascript 函数,就不可避免地写大量的大括号,这个时候上面的解决方法就不适用了,Smarty 提供了一个转义一段代码的标签:{literal}…{/literal}
{literal}

{/literal}

这样,就可以在里面随意写各种符号,不必担心 Smarty 引擎会错误解析了!

PHP 性能优化(一)

PHP DEFINE(原作者:CS,在此感谢CS同学的帮助)

DEFINE是大家常用的定义常量的方法,但是DEFINE是存在一定的性能问题的。虽然一般的项目中可能会觉得DEFINE也不会很多,影响不是很大。

但是,实际上,由于require的使用和嵌套等,会在不知不觉中引用到很多的DEFINE。 例如,公司某个最近发布的项目中,一个典型的页面会引用到接近400个DEFINE,使用APD进行profiling后会发现DEFINE消耗的CPU非常靠前。

我们进行了一些对比测试:准备了4个php文件

d1.php

d2.php

d3.php

s1.php

每个文件都是重复1000项,以使对比效果明显。

主程序分别requrie这四个文件,对比进行压力测试。对比测试的结果如下:

d1.php – QPS 1050 左右
d2.php – QPS 1300 左右
d3.php – QPS 2500 左右
s1.php – QPS 3500 左右

结论:

很明显,DEFINE的性能是最差的,而且对比来看,是非常的差。 因此,建议在需要定义常量的地方,可以建立一个专门的常量类。

测试环境:

apache 2.0.59 php 5.2.1
HP DL360 XEON 3.0G*2 2G

PHP 异步调用 后台调用 持续执行 断开连接/浏览器

标题很怪,因为我也不知道怎样用一句简短的话来概括下面这部分内容。只是希望各位 PHP 的开发者们更容易通过搜索引擎搜到这篇介绍。

这回的核心内容就是围绕 ignore_user_abort 这个函数展开的。

做  Web 开发的人都知道,浏览器和服务器之间是通过 HTTP 协议进行连接通讯的。这是一种基于请求和响应模型的协议。浏览器通过 URL 向某台服务器发起请求(Request),Web 服务器接收到请求,执行一段程序,然后做出响应(Response),也就是一段字符串,这个字符串符合 HTTP 协议的格式,有 HEAD 和 BODY 两部分。

这其中有一个问题,Web  服务器执行一段程序,可能几毫秒就完成,也可能几分钟都完不成。如果程序执行缓慢,用户可能没有耐心等下去,就关闭浏览器了。这个时候,服务器会接收到连接状态改变的通知,因为 HTTP  是最上层的协议,下面还有一层 TCP 协议,TCP  会知道连接中断。连接一断,服务端的程序会立即停止执行。

现在说到问题的关键了,服务端的程序立即停止执行,如果这个程序只是读取信息的还好说,停了就不读了呗。万一是一个写入的程序呢?比如,用户提交一段文本,也许服务端的设计比较复杂,需要同时更新好几个表,但由于某些原因,例如其中一个表被其他进程锁定,那么这个程序就会一直等待,这个时候用户要是关闭浏览器,那程序就不等了,直接退出了。结果就是这条信息保存不完整。

举个具体的例子,用户提交的文本需要写到 A、B、C、D 四个表里,写入 A、B 两个表可能 0.1 毫秒就完成了,但 C 表被另一个进程锁定,那当前进程就得一直等,这时用户关闭浏览器,当前进程退出,那么,就会造成一种状况,A、B 表里有新的内容,而 C、D 表里没有这条内容,产生了严重的数据一致性的问题!

虽然,利用数据库的事务,可以使状态回滚,但结果就是用户的本次提交无效。

我希望的是,只要用户提交了,就要成功保存,也许遇到意外情况导致执行时间过长,但用户关闭浏览器也没关系。

于是,我找到了 ignore_user_abort 这个函数。

当调用 ignore_user_abort(1) 时, 就设定了忽略用户退出这个标志位,也就是不管怎样,也要把程序执行到底,除非在程序中调用了 exit。

其实,还有另一个函数,register_shutdown_function,它可以注册一个函数或方法,在程序退出的时候调用,有些类似于 javascript 里面的 onunload 和 onbeforeunload 事件。

我这里引用了 中文版PHP手册 的相关内容:

章 40. 连接处理
注意: 以下内容对 PHP 3.0.7 及更高版本适用。

在 PHP 内部,系统维护着连接状态,其状态有三种可能的情况:

0 – NORMAL(正常)

1 – ABORTED(异常退出)

2 – TIMEOUT(超时)

当 PHP 脚本正常地运行 NORMAL 状态时,连接为有效。当远程客户端中断连接时,ABORTED 状态的标记将会被打开。远程客户端连接的中断通常是由用户点击 STOP 按钮导致的。当连接时间超过 PHP 的时限(请参阅 set_time_limit() 函数)时,TIMEOUT 状态的标记将被打开。

可以决定脚本是否需要在客户端中断连接时退出。有时候让脚本完整地运行会带来很多方便,即使没有远程浏览器接受脚本的输出。默认的情况是当远程客户端连接中断时脚本将会退出。该处理过程可由 php.ini 的 ignore_user_abort 或由 Apache .conf 设置中对应的“php_value ignore_user_abort”以及 ignore_user_abort() 函数来控制。如果没有告诉 PHP 忽略用户的中断,脚本将会被中断,除非通过 register_shutdown_function() 设置了关闭触发函数。通过该关闭触发函数,当远程用户点击 STOP 按钮后,脚本再次尝试输出数据时,PHP 将会检测到连接已被中断,并调用关闭触发函数。

脚本也有可能被内置的脚本计时器中断。默认的超时限制为 30 秒。这个值可以通过设置 php.ini 的 max_execution_time 或 Apache .conf 设置中对应的“php_value max_execution_time”参数或者 set_time_limit() 函数来更改。当计数器超时的时候,脚本将会类似于以上连接中断的情况退出,先前被注册过的关闭触发函数也将在这时被执行。在该关闭触发函数中,可以通过调用 connection_status() 函数来检查超时是否导致关闭触发函数被调用。如果超时导致了关闭触发函数的调用,该函数将返回 2。

需要注意的一点是 ABORTED 和 TIMEOUT 状态可以同时有效。这在告诉 PHP 忽略用户的退出操作时是可能的。PHP 将仍然注意用户已经中断了连接但脚本仍然在运行的情况。如果到了运行的时间限制,脚本将被退出,设置过的关闭触发函数也将被执行。在这时会发现函数 connection_status() 返回 3。

PHP 的官方网站在线文档有英文原版说明,下面还有一些用户的反馈,也很有价值,这里是链接:

 http://www.php.net/manual/en/features.connection-handling.php

国际域名转移 新网 Godaddy (二)

本来想睡了,不过看到博客好几天没更新了,就来写个续集。

上会说到在 Godaddy 只要人民币大约 55 块钱就可以买一个 .com 的国际域名和一个经济型的虚拟主机。

稍微有点跑题,不过,这是为了后文做铺垫。

有一点对比的就是,国内的注册商,都是打着顶级域名注册商的旗号,提供域名注册。其实,他们只不过是国内几家大型域名注册公司的下线代理而已。

因为刚开始我也不是很懂,注册域名的时候,有的地方年费是 100,有的是 68,就选了一个 68 的,图个便宜。注册过程倒是顺利,很快就注册完了。

进入管理界面,就显得比较粗糙。子域名通常只能设置 20 个,域名转向比较麻烦,需要把 IP 设置成服务商的某台服务器,然后由那台服务器重定向过去。域名生效比较慢,等等。没用过更好的,所以觉得还可以。

后来,验证域名信息的时候,查 whois 数据库,发现我的域名注册商是 http://www.xinnet.com/,而不是我使用的那个注册商。而且域名信息里,只有管理员的联系方式是我自己的,其他的如技术联系人,付费联系人等都是那个小注册商的人。

虽然这不影响使用,但总觉得不踏实。

又查询了很多信息后,终于知道,在国内,有权注册 .com、.net 和 .org 等国际域名的注册商只有 新网、万网等几家,因此他们的价格比较贵,都是 100 或以上,如果是 .mobi 的则更贵,一年 180,还得一次性注册 2 年以上才可以。而他们的下线代理商,如我注册的那家,价格可能便宜一点,.com 的在 68 左右。

一个偶然的机会,了解的 Godaddy 是全球最大的域名注册商,有了 连载一 的经验,并注册过新域名使用过他的服务后,我决定把我在国内注册的域名转移到 Godaddy。

于是,再 Godaddy 购买了一个域名转移服务,价格和注册 .com 的一样。网站声称是免费转移,为什么还需要收钱呢,看了介绍,那个 8.95 美元的转移服务费,其实就是给你要转移的域名续费一年。比如你的域名是 2007 年10 月到期,你现在转移,当成功操作后,这个域名的到期时间就是 2008 年 10 月了。

具体的转移过程是这样的:

1、你首先要确定,域名的管理员邮箱仍然是有效的,能够正常收信;
2、域名的到期时间是距现在 3 个月以上,比如今天是 6 月 29,那么到期时间应该在 9 月29 以后才允许转移;
3、到 Godaddy 购买域名转移服务并付费,然后会立即收到一封确认信,里面有事务 ID 和密码;
4、到 Godaddy 的 Pendding Transfer 管理界面找到你刚才购买的服务,点击该域名,输入事务 ID 和密码,因为只有管理员才能收到这 2 个验证信息;
5、信息填写正确后,需要输入 Authentication Code,也就是域名密码,刚遇到这个问题的时候,我突然傻了,不知道该填哪个,然后问了我当前的小的注册商,他们说,要转出域名,需要到新网下载一个申请表,打印出来,填上相关信息,包括姓名,身份证复印件,然后,把申请表原件寄到这个小的代理商(我在北京,新网也在北京,那个小注册商在上海!!!),代理商盖上公章,然后再把这个原件寄给当地新网分公司,这个过程是我觉得最麻烦的,国内的这种传统真是太落后了,有一个人评价这套流程挺一针见血的,他说,与其要求盖章的申请表,还不如直接把域名密码发送到所有人的邮箱,因为,在国内,要想找黑客破解别人的邮箱是很难的,但是,做个假公章,几块钱就可以搞定,不知道为什么还要用如此落后的手段验证域名所有人信息?
6、经过N多天的漫长等待,大概要1周到2周,终于等到了新网给我发的域名密码!虽然邮寄的过程出了点小插曲,但是新网的办公人员素质还是很不错的,耐心解答我的好多问题,还帮助我把申请表传真给他们的分公司,为我节省了不少时间,再此表扬一下!是北京的一个姓陈的姐姐,如果你看到了,应该还有印象,我是那个把原件寄给你,要求你帮我传真到上海分公司的那个人;
7、拿到域名密码后,再次回到第5步的那个环节,就是输入 Authentication Code,完成后,系统提示正在向原服务商证实转移信息,一般这个过程大概持续7、8天,在这个过程中,你查询 whois 仍旧是原来的域名信息,等 8 天过后,一切都变了。

以上就是大体步骤,需要注意的几点是:

1、如果你要转移域名,最好是提前先去申请拿到域名密码,因为这个过程一般都需要一个多星期,在 Godaddy 买完域名转移服务后,如果中途出现问题,他们只会保留 30 天,过后好像也不退款,因此,先拿到域名密码比较保险;
2、域名转移成功后,3 个月内不允许再次转移,所以,如果你要连续过户,最好直接把域名过给最后一个买家

目前想到的也就是这些,以后想到什么再补充吧。

国际域名转移 新网 Godaddy 的文章连载到这里就结束了,只有一、二两集,是我第一次写这种东西,经验有限,表达能力也比较差,大家凑合看吧,有问题尽管发评论问我,我会尽快解答。

欢迎大家转载我的文章,只希望大家转载的时候附上我的署名 Leakon,并加上我的博客地址,作为对我原创内容的鼓励吧。谢谢!

你的成绩没有达到我们的要求

我去做了,得到这样令人遗憾的答复。

我可以问心无愧地说,这2年,我付出了比别人多得多的努力,同时也得到了很多的知识和经验。

我以为,我可以检验一下自己的实力,证明我的辛苦付出没有白费。

结果就是这样的。

好吧,我接受这个结论。

我崇拜越王勾践,我不会臣服,我会让你们为今天的结论感到羞愧!

Javascript window.onresize

function display() {
setTimeout(
function() {
// 生成背景图层
var obackgound = document.createElement(‘div’);
obackgound.id = ‘my_background’;
document.body.appendChild(document.body, obackgound);
// 在 app 这个容器里显示有价值的内容
var app = $(‘container’);
var fix_position = function() {
if (app.style.display == ‘none’) return;
var ch = document.documentElement.clientHeight,
sh = document.documentElement.scrollHeight,
st = document.documentElement.scrollTop;
// 背景图层的 宽高 是浏览器实际内容的 宽和高
obackgound.style.height = (sh > ch ? sh : ch) + ‘px’;
obackgound.style.width = document.body.clientWidth + ‘px’;
// 根据要显示内容的宽高,确定他在浏览器里的位置
var pos = [], pw;
pw = 840;
pos[0] = (document.body.clientWidth – pw) / 2;


pos[1] = parseInt(st);
if (navigator.product && navigator.product == ‘Gecko’) {
pw -= 140;
}
app.style.position = ‘absolute’;
app.style.left = pos[0] + ‘px’;
app.style.top = pos[1] + ‘px’;
app.style.width = pw + ‘px’;
}
// !!! 重要 !!! 这里是问题的关键,Windows 和 Firefox 对 window.onresize 事件的处理方式不同
// 在浏览器装载了新内容,并重新绘图的时候,总体内容的尺寸会发生变化,但是调用上面这个事件的时间点不同
// IE 容易导致死循环
// 所以,加了延迟,避免 IE 崩溃。这里就体现出 Firefox 浏览器在设计上的优秀之处。
setTimeout(
function() {
window.onresize = fix_position;
}, 100 );
obackgound.style.display = ‘block’;
fix_position();
},
50
);
}