﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-桃之夭夭-随笔分类-学而篇第一</title><link>http://www.blogjava.net/raimundox/category/5762.html</link><description>知天之所为，知人之所为者，至矣。知天之所为者，天而生也；知人之所为者，以其知之所知以养其知之所不知，终其天年而不中道夭者：是知之盛也。</description><language>zh-cn</language><lastBuildDate>Wed, 28 Nov 2007 11:51:35 GMT</lastBuildDate><pubDate>Wed, 28 Nov 2007 11:51:35 GMT</pubDate><ttl>60</ttl><item><title>Misquotation</title><link>http://www.blogjava.net/raimundox/archive/2007/11/28/163761.html</link><dc:creator>Raimundox</dc:creator><author>Raimundox</author><pubDate>Wed, 28 Nov 2007 10:08:00 GMT</pubDate><guid>http://www.blogjava.net/raimundox/archive/2007/11/28/163761.html</guid><wfw:comment>http://www.blogjava.net/raimundox/comments/163761.html</wfw:comment><comments>http://www.blogjava.net/raimundox/archive/2007/11/28/163761.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/raimundox/comments/commentRss/163761.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/raimundox/services/trackbacks/163761.html</trackback:ping><description><![CDATA[前几天在JavaEye海阔被标题党阴了一把，看了一篇转的文章叫《<a href="http://bbs.education.163.com/bbs/newht/5009.html">被中国人误传了数千年的七句话</a>》，颇有些哭笑不得的感慨：<br />
<br />
1. 这些话的确是被误传了不假，但是最多也就一百年吧。中国知识分子不读四书五经史子集的坏风气大抵是开始于所谓的新文化运动吧。再往前的人，对于这些典籍字字爬梳，提了上句马上背下句，就算是以章句式解读为主的宋元，也不应该随随便便就被忽悠了，更不用说反对宋儒理学讲究正本清源的明清了。<br />
<br />
2. 古人断章取义是一种风雅的言谈习惯，所谓&#8220;雅言&#8221;是要字字出典的，有点像对暗号。比如我们家猫跑了，搁古代我肯定问&#8220;谁之过欤？&#8221;，十有八九我老婆会说，&#8220;言是典守者之过也&#8221;，这句射的是&#8220;虎兕出于柙&#8221;，正好应景。甚至为了诙谐应景，故意曲解文义的情况也是很常见的。如果以此为证说误传的话，恐怕只能算是牛嚼牡丹了。顺便多说一句，其实这个毛病现代人也有，不过不再是古文了，大多数是电影电视台词：&#8220;空气在颤抖仿佛天空在燃烧。是啊，暴风雨就要来了&#8221;，&#8220;道哥，牌子啊&#8221;，&#8220;你看我的英语，有没有长进&#8221;之类的，虽不复古韵，但也还算有趣。<br />
<br />
<br />
P.S. : 今天team里有人把David Wheeler的名言，贴在了Quote Wall上：&#8220;Any problem in computer science can be solved with another layer of indirection.&#8221;<br />
<br />
这到的确算是一句被误传的名言吧，原文是&#8220;Any problem in computer science can be solved with another layer of indirection. <strong>But that usually will create another problem.</strong>&#8221;<br />
<img src ="http://www.blogjava.net/raimundox/aggbug/163761.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/raimundox/" target="_blank">Raimundox</a> 2007-11-28 18:08 <a href="http://www.blogjava.net/raimundox/archive/2007/11/28/163761.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Feng Shui for Standard ML Programmers</title><link>http://www.blogjava.net/raimundox/archive/2007/07/10/129436.html</link><dc:creator>Raimundox</dc:creator><author>Raimundox</author><pubDate>Tue, 10 Jul 2007 13:53:00 GMT</pubDate><guid>http://www.blogjava.net/raimundox/archive/2007/07/10/129436.html</guid><wfw:comment>http://www.blogjava.net/raimundox/comments/129436.html</wfw:comment><comments>http://www.blogjava.net/raimundox/archive/2007/07/10/129436.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.blogjava.net/raimundox/comments/commentRss/129436.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/raimundox/services/trackbacks/129436.html</trackback:ping><description><![CDATA[<a>http://www.dcs.ed.ac.uk/home/stg/fengshui.ps.gz</a><br><br>今天早上打开Google Reader就看见这么一篇，内容倒也罢了，不过是bad smell的另一个名字而已，硬要扯上分水也只能算是勉勉强强。不过郁闷的是，竟然是个洋人的手笔，国学不昌实不能不令我辈心忧啊。<br><br>p.s. 预计未来6个月口头禅："你这写当心坏了项目的风水"<br><img src ="http://www.blogjava.net/raimundox/aggbug/129436.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/raimundox/" target="_blank">Raimundox</a> 2007-07-10 21:53 <a href="http://www.blogjava.net/raimundox/archive/2007/07/10/129436.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>The Keyword 'end' Drives Me Crazy</title><link>http://www.blogjava.net/raimundox/archive/2007/05/11/116864.html</link><dc:creator>Raimundox</dc:creator><author>Raimundox</author><pubDate>Fri, 11 May 2007 12:32:00 GMT</pubDate><guid>http://www.blogjava.net/raimundox/archive/2007/05/11/116864.html</guid><wfw:comment>http://www.blogjava.net/raimundox/comments/116864.html</wfw:comment><comments>http://www.blogjava.net/raimundox/archive/2007/05/11/116864.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/raimundox/comments/commentRss/116864.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/raimundox/services/trackbacks/116864.html</trackback:ping><description><![CDATA[最近很多时间都在用Ruby，逐渐地发现了一件很不爽的事情，就是Ruby的end关键字。block多套几层，很容易就最后一页都是end了...难怪有人说，ruby不过是另一种acceptable Lisp，&#8220;最后一页都是括号&#8221;的经典标志以另外一种形式复现了...对于Lisp的括号，我还是可以接受的，但是满眼的end，直接让我回忆起10年前冲刺NOI的种种，CPU直接切换到实模式，什么可读啊小粒度方法全都没有了，审美观赤裸地变为短小精悍...最后杀红了眼，一行算出文法定义的所有nullable symbols...<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">1</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;@productions.inject(</span><span style="color: #0000ff;">false</span><span style="color: #000000;">)&nbsp;{</span><span style="color: #000000;">|</span><span style="color: #000000;">c,&nbsp;p</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;c&nbsp;</span><span style="color: #000000;">|=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">!</span><span style="color: #000000;">nullable</span><span style="color: #000000;">?</span><span style="color: #000000;">(p.nonterminal)&nbsp;</span><span style="color: #000000;">&amp;&amp;</span><span style="color: #000000;">&nbsp;p.symbols.all</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;{</span><span style="color: #000000;">|</span><span style="color: #000000;">s</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;nullable</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;s}&nbsp;</span><span style="color: #000000;">&amp;&amp;</span><span style="color: #000000;">&nbsp;@nullables&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;p.nonterminal}</span></div>
<br>注意1不是行号...这句用的statement modifier, 1是我能想到的最小ruby语句了...<br><br>p.s. <br>我现在已经恢复到OO保护模式了...刚才追求短小过了头的同时，发现了ruby bulid-in object的一个陷阱...<br>a = Array.new 5, []<br>[[],[],[],[],[]]<br>a[0] &lt;&lt; 1<br>[[1],[1],[1],[1],[1]]<br><br>想不到华丽的Array直接假设传进去的都是值对象了，好歹您也调个dup啊...<br><br><br>  <img src ="http://www.blogjava.net/raimundox/aggbug/116864.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/raimundox/" target="_blank">Raimundox</a> 2007-05-11 20:32 <a href="http://www.blogjava.net/raimundox/archive/2007/05/11/116864.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Church Number</title><link>http://www.blogjava.net/raimundox/archive/2006/10/09/73931.html</link><dc:creator>Raimundox</dc:creator><author>Raimundox</author><pubDate>Sun, 08 Oct 2006 18:32:00 GMT</pubDate><guid>http://www.blogjava.net/raimundox/archive/2006/10/09/73931.html</guid><wfw:comment>http://www.blogjava.net/raimundox/comments/73931.html</wfw:comment><comments>http://www.blogjava.net/raimundox/archive/2006/10/09/73931.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/raimundox/comments/commentRss/73931.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/raimundox/services/trackbacks/73931.html</trackback:ping><description><![CDATA[今天被老庄拉到JavaEye扯皮，扯来扯去还是lambda演算...本来应承了老庄写lambda演算简介，不过看到磐石T1同学提到了Church number来勾引whl同学...于是我想还是写一些更有意思的东西吧。<br /><br />每个Church number都是一个接受两个参数的函数，这两个参数又都是函数，第一个参数称为后继函数，第二个参数则叫做零点函数。依据这两个函数，我们可以定义Church number zero, one, two：<br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><font color="#000000"><span style="color: rgb(0, 0, 0);">(define zero  (lambda (successor zero) zero))<br />(define one （lambda (successor zero) (successor zero)))<br />(define two   (lambda (successor zero) (successor (successor zero))))<br /></span></font></div><br />可以看出，所谓one就是对零点函数应用一次后继函数，而two则是对零点函数应用后继函数的结果再次应用后继函数，依次类推可以得到Church Number n。下面我们可以通过后继函数increase和零点函数f(x) = 0来看看这些Church Number的计算结果：<br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">(define (increase x) (</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> x </span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">))<br /><br />(zero increase 0)<br />&gt; 0<br /></span><span style="color: rgb(0, 0, 0);">(one increase 0)</span><br /><span style="color: rgb(0, 0, 0);">&gt;1<br /></span><span style="color: rgb(0, 0, 0);">(two increase 0)</span><br /><span style="color: rgb(0, 0, 0);">&gt;2<br /><br />an approximate Java version:<br /><br />public interface Function&lt;T&gt; {<br />    T apply(Object... parameters);<br />}<br /><br />public interface ChurchNumber {<br />    Integer apply(Function&lt;Integer&gt; successor, Function&lt;Integer&gt; zero);<br />}<br /><br />ChurchNumber zero = new ChurchNumber() {<br />   public Integer apply(Function&lt;Integer&gt; successor,  Function&lt;Integer&gt; zero) {<br />      return zero.apply();<br />   }<br />};<br /><br />ChurchNumber one = new ChurchNumber() {<br />   public Integer apply(Function&lt;Integer&gt; successor, Function&lt;Integer&gt; zero) {<br />      return successor.apply(zero);<br />   }<br />};<br /><br />ChurchNumber two = new ChurchNumber() {<br />   public Integer apply(Function&lt;Integer&gt; successor, Function&lt;Integer&gt; zero) {<br />      return successor.apply(successor.apply(zero));<br />   }<br />};<br /><br />Function increase = new Function&lt;Integer&gt;() {<br /> public Integer apply(Object... parameters) {<br />   if (parameters[0] instanceof Function) {<br />      return ((Function&lt;Integer&gt;) parameters[0]).apply() + 1;<br />   }<br />   return (Integer) parameters[0] + 1;<br /> }<br />};<br /><br />Function numberZero = new Function&lt;Integer&gt;() {<br />   public Integer apply(Object... parameters) { return 0;}<br />};<br /><br /><br />System.out.println(zero.apply(increase, numberZero));<br />&gt;0<br />System.out.println(one.apply(increase, numberZero));<br />&gt;1<br />System.out.println(two.apply(increase, numberZero));<br />&gt;2<br /></span></div><br />定义了Church number后，我们继续定义Church number上的运算，首先是增加1：<br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">(define (inc x) (lambda </span><span style="color: rgb(0, 0, 0);">(successor zero) (successor (x successor zero))</span><span style="color: rgb(0, 0, 0);">))<br /><br />(define three (inc two))<br />(three increase 0)<br />&gt;3<br /><br /></span><span style="color: rgb(0, 0, 0);">an approximate Java version:</span><br /><span style="color: rgb(0, 0, 0);"><br />static ChurchNumber inc(final ChurchNumber churchNumber) {<br />   return new ChurchNumber() {<br />      public Integer apply(Function&lt;Integer&gt; successor, Function&lt;Integer&gt; zero) {<br />         return successor.apply(churchNumber.apply(successor, zero));<br />       }<br />   };<br />}<br /><br />ChurchNumber three = inc(two);<br />System.out.println(three.apply(increase, numberZero));<br />&gt;3<br /></span></div><br />然后是加法：<br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">(define (add x y) (lambda (</span><span style="color: rgb(0, 0, 0);">successor zero</span><span style="color: rgb(0, 0, 0);">)  (x successor (y successor zero))))<br /><br />(define five (add three two))<br />(five increase 0)<br />&gt;5<br /><br /></span><span style="color: rgb(0, 0, 0);">an approximate Java version:</span><br /><span style="color: rgb(0, 0, 0);"><br />static ChurchNumber add(final ChurchNumber x, final ChurchNumber y) {<br />        return new ChurchNumber() {<br />            public Integer apply(final Function&lt;Integer&gt; successor,<br />                    final Function&lt;Integer&gt; zero) {<br />                return x.apply(successor, new Function&lt;Integer&gt;() {<br />                    public Integer apply(Object... parameters) {<br />                        return y.apply(successor, zero);<br />                    }<br />                });<br />            }<br />        };<br />}<br /><br />ChurchNumber five = add(two, three);<br />System.out.println(five.apply(increase, numberZero));<br />&gt;5<br /></span></div><br />最后是乘法：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">(define (multiply x y) </span><span style="color: rgb(0, 0, 0);">(lambda (</span><span style="color: rgb(0, 0, 0);">successor zero</span><span style="color: rgb(0, 0, 0);">)  (x  (lambda (z) (y successor z)) zero)))<br /><br />(define four (multiply two two))<br />(four increase 0)<br />&gt;4<br /><br /></span><span style="color: rgb(0, 0, 0);">an approximate Java version:</span><br /><span style="color: rgb(0, 0, 0);"><br />static ChurchNumber multiply(final ChurchNumber x, final ChurchNumber y) {<br />        return new ChurchNumber() {<br />            public Integer apply(final Function&lt;Integer&gt; successor,<br />                    Function&lt;Integer&gt; zero) {<br />                return x.apply(new Function&lt;Integer&gt;() {<br />                    public Integer apply(final Object... parameters) {<br />                        return y.apply(successor, new Function&lt;Integer&gt;() {<br />                            public Integer apply(Object... ignoredParameters) {<br />                                if (parameters[0] instanceof Function) {<br />                                    return ((Function&lt;Integer&gt;) parameters[0]).apply();<br />                                }<br />                                return (Integer) parameters[0];<br />                            }<br />                        });<br />                    }<br />                }, zero);<br />            }<br />        };<br />}<br /><br />ChurchNumber four = multiply(two, two);<br />System.out.println(four.apply(increase, numberZero));<br /></span></div><br />没有减法和除法，Church当年发明这套东西的时候就没有。原因是非常明显的...因此Church number只有后继函数，而没有前驱函数。也就是说Church number只能往前数...不能望后数...自然不可能作出减法和除法了。当然扩展一下也是非常容易的：<br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">(define negative</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">one (lambda (successor precursor zero) (precursor zero)))<br />(define one (lambda (successor precursor zero) (successor zero)))<br /><br />(define (add x y) (lambda (successor precursor zero) (x successor precursor ( y successor precursor zero) )))<br /><br />(define (inc x) (</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> x </span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">))<br />(define (dec x) (</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);"> x </span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">))<br /><br />(define zero (add one negative</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">one))<br /><br />(zero inc dec </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">)<br /></span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);"><br /></span></div><br /><br />whl同学问这样能不能实现浮点，答案是可以实现有限精度的浮点数....因为按照这个思路发展下去，我们定义浮点的successor和precursor函数只能在有限的位数之内...当然有了one,zero再结合pair，模拟0/1存储实现浮点也不是不可能的事情...<font color="#ffffff"><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);"></span></font><img src ="http://www.blogjava.net/raimundox/aggbug/73931.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/raimundox/" target="_blank">Raimundox</a> 2006-10-09 02:32 <a href="http://www.blogjava.net/raimundox/archive/2006/10/09/73931.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Selenium Better Pratice</title><link>http://www.blogjava.net/raimundox/archive/2006/08/04/61860.html</link><dc:creator>Raimundox</dc:creator><author>Raimundox</author><pubDate>Fri, 04 Aug 2006 13:59:00 GMT</pubDate><guid>http://www.blogjava.net/raimundox/archive/2006/08/04/61860.html</guid><wfw:comment>http://www.blogjava.net/raimundox/comments/61860.html</wfw:comment><comments>http://www.blogjava.net/raimundox/archive/2006/08/04/61860.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.blogjava.net/raimundox/comments/commentRss/61860.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/raimundox/services/trackbacks/61860.html</trackback:ping><description><![CDATA[
		<p>1. Never use Selenium FIT mode</p>
		<p>Selenium分为两种运行模式，Driven Mode(现在叫Selenium Remote Control)和FIT Mode(现在叫Selenium Core)。</p>
		<p>FIT Mode顾名思义，就是类似FIT Testing Framework那种使用方式，主要用于QA等非技术人员编写Web应用的功能测试。FIT Mode的Selenium测试使用HTML来组织测试用例。例如我要测试一个web应用的登陆功能。我可能写出这样的HTML 表格。</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #008080"> 1</span>
				<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">table</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080"> 2</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">tr</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080"> 3</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /> </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">open</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080"> 4</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">http://localhost:8080/login</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080"> 5</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080"> 6</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">tr</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080"> 7</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">tr</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080"> 8</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /> </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">type</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080"> 9</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">id=username</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">10</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">someuser</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">11</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">tr</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">12</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">tr</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">13</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /> </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">type</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">14</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">id=password</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">15</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">password</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">16</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">tr</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">17</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">tr</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">18</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /> </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">click</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">19</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">id=login_button</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">20</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">21</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">tr</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">22</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">tr</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">23</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /> </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">assertTextPresent</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">24</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">Welcome to xxxx</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">25</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">26</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">tr</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">27</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">table</span>
				<span style="COLOR: #0000ff">&gt;</span>
		</div>
		<p>不同于FIT，Selenium内置了一系列的命令，如上例中的open, type, click以及assertTextPresent，因此QA可以完全抛开DEV独立地编写测试(FIT需要DEV提供Behavior Fixture)。因此FIT Mode是相当容易使用的，哪怕不会使用HTML的QA，也可以使用FrontPage画出三列表格，依次填入数据。</p>
		<p>然而对于大多数team而言——尤其是敏捷team，FIT Mode平易的外表下是令人恐惧的泥沼。大多数团队往往选择使用Selenium作为功能测试和集成测试工具而不仅仅是QA测试工具，在不同的迭代间遇到功能流程或UI变化时，必须要重构Selenium测试，或者说，Functional Test Migration。令人遗憾的是，HTML based的Selenium FIT Testing的重构竟然令人难以置信的困难。我们可以使用include等Selenium FIT扩展，使得它可以重用详细的功能（Log in， Log out诸如此类）。即便如此，在一个真实的项目中，Selenium Test的数量往往在200-500之间(我目前所处的项目在改用Driven Mode前已达350+)，对于这么大基数的Selenium测试，手工重构几乎是不可想象的，而目前尚没有HTML代码重构工具。即便存在泛泛意义上的HTML重构工具，对于Selenium测试重构的有效性尚待商榷。而使用Driven Mode上述代码可以写为:</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #008080">1</span>
				<img id="Codehighlighter1_61_302_Open_Image" onclick="this.style.display='none'; Codehighlighter1_61_302_Open_Text.style.display='none'; Codehighlighter1_61_302_Closed_Image.style.display='inline'; Codehighlighter1_61_302_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
				<img id="Codehighlighter1_61_302_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_61_302_Closed_Text.style.display='none'; Codehighlighter1_61_302_Open_Image.style.display='inline'; Codehighlighter1_61_302_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> testShouldShowAWeclomeMessageAfterUserLoggedIn() </span>
				<span id="Codehighlighter1_61_302_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.blogjava.net/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_61_302_Open_Text">
						<span style="COLOR: #000000">{<br /></span>
						<span style="COLOR: #008080">2</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    selenium.open(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">http://localhost:8080/login</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">);<br /></span>
						<span style="COLOR: #008080">3</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    selenium.type(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">id=username</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">,</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">someuser</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">);<br /></span>
						<span style="COLOR: #008080">4</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    selenium.type(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">id=password</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">, </span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">password</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">);<br /></span>
						<span style="COLOR: #008080">5</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    selenium.click(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">id=login_button</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">);<br /></span>
						<span style="COLOR: #008080">6</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    assertTrue(selenium.isTextPresent(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">Welcome to xxxx</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">));<br /></span>
						<span style="COLOR: #008080">7</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
		</div>
		<p>
				<br />很自然，一个训练有素的程序员会重构出如下代码:</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #008080"> 1</span>
				<img id="Codehighlighter1_52_231_Open_Image" onclick="this.style.display='none'; Codehighlighter1_52_231_Open_Text.style.display='none'; Codehighlighter1_52_231_Closed_Image.style.display='inline'; Codehighlighter1_52_231_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
				<img id="Codehighlighter1_52_231_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_52_231_Closed_Text.style.display='none'; Codehighlighter1_52_231_Open_Image.style.display='inline'; Codehighlighter1_52_231_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> login(String username, String password) </span>
				<span id="Codehighlighter1_52_231_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.blogjava.net/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_52_231_Open_Text">
						<span style="COLOR: #000000">{<br /></span>
						<span style="COLOR: #008080"> 2</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    selenium.open(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">http://localhost:8080/login</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">);<br /></span>
						<span style="COLOR: #008080"> 3</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    selenium.type(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">id=username</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">,username);<br /></span>
						<span style="COLOR: #008080"> 4</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    selenium.type(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">id=password</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">, password);<br /></span>
						<span style="COLOR: #008080"> 5</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    selenium.click(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">id=login_button</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">); <br /></span>
						<span style="COLOR: #008080"> 6</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080"> 7</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
						<br />
				</span>
				<span style="COLOR: #008080"> 8</span>
				<span style="COLOR: #000000">
						<img id="Codehighlighter1_295_391_Open_Image" onclick="this.style.display='none'; Codehighlighter1_295_391_Open_Text.style.display='none'; Codehighlighter1_295_391_Closed_Image.style.display='inline'; Codehighlighter1_295_391_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
						<img id="Codehighlighter1_295_391_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_295_391_Closed_Text.style.display='none'; Codehighlighter1_295_391_Open_Image.style.display='inline'; Codehighlighter1_295_391_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> testShouldShowAWeclomeMessageAfterUserLoggedIn() </span>
				<span id="Codehighlighter1_295_391_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.blogjava.net/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_295_391_Open_Text">
						<span style="COLOR: #000000">{<br /></span>
						<span style="COLOR: #008080"> 9</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    login(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">someuser</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">, </span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">password</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">);<br /></span>
						<span style="COLOR: #008080">10</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    assertTrue(selenium.isTextPresent(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">Welcome to xxxx</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">));<br /></span>
						<span style="COLOR: #008080">11</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
		</div>
		<p>之后无论是pull up到公共基类还是extact到Utils class都是很容易的事情。由于Java在代码重构上便利，Java Selenium Remote Control成为使用Selenium的最佳方式。在这一点上，纵使Ruby语法上比Java简单灵活得多，它仍不是编写Selenium测试的最佳载体(当然一个经过精心设计的ruby selenium dsl wrapper还是具有非凡的价值的，这个我们后面会涉及到)。</p>
		<p>2. Using the name user, system, page instead of selenium</p>
		<p>观察上面提到的代码，其中使用selenium来操纵web应用的行为，这在Remote Control里是常见的做法，但是仍然不够好，我们可以做一些小的变化以得到更好的测试:</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #008080"> 1</span>
				<img id="Codehighlighter1_23_127_Open_Image" onclick="this.style.display='none'; Codehighlighter1_23_127_Open_Text.style.display='none'; Codehighlighter1_23_127_Closed_Image.style.display='inline'; Codehighlighter1_23_127_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
				<img id="Codehighlighter1_23_127_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_23_127_Closed_Text.style.display='none'; Codehighlighter1_23_127_Open_Image.style.display='inline'; Codehighlighter1_23_127_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				<span style="COLOR: #0000ff">protected</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> setup() </span>
				<span id="Codehighlighter1_23_127_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.blogjava.net/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_23_127_Open_Text">
						<span style="COLOR: #000000">{<br /></span>
						<span style="COLOR: #008080"> 2</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    selenium </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> <img src="http://www.blogjava.net/images/dot.gif" /><img src="http://www.blogjava.net/images/dot.gif" /> </span>
						<span style="COLOR: #008000">//</span>
						<span style="COLOR: #008000"> intialize selenium instance</span>
						<span style="COLOR: #008000">
								<br />
						</span>
						<span style="COLOR: #008080"> 3</span>
						<span style="COLOR: #008000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
						</span>
						<span style="COLOR: #000000">    user </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> selenium;<br /></span>
						<span style="COLOR: #008080"> 4</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    currentPage </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> selenium;<br /></span>
						<span style="COLOR: #008080"> 5</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080"> 6</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
						<br />
				</span>
				<span style="COLOR: #008080"> 7</span>
				<span style="COLOR: #000000">
						<img id="Codehighlighter1_182_345_Open_Image" onclick="this.style.display='none'; Codehighlighter1_182_345_Open_Text.style.display='none'; Codehighlighter1_182_345_Closed_Image.style.display='inline'; Codehighlighter1_182_345_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
						<img id="Codehighlighter1_182_345_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_182_345_Closed_Text.style.display='none'; Codehighlighter1_182_345_Open_Image.style.display='inline'; Codehighlighter1_182_345_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> login(String username, String password) </span>
				<span id="Codehighlighter1_182_345_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.blogjava.net/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_182_345_Open_Text">
						<span style="COLOR: #000000">{<br /></span>
						<span style="COLOR: #008080"> 8</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    user.open(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">http://localhost:8080/login</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">);<br /></span>
						<span style="COLOR: #008080"> 9</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    user.type(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">id=username</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">,username);<br /></span>
						<span style="COLOR: #008080">10</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    user.type(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">id=password</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">, password);<br /></span>
						<span style="COLOR: #008080">11</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    user.click(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">id=login_button</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">); <br /></span>
						<span style="COLOR: #008080">12</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">13</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
						<br />
				</span>
				<span style="COLOR: #008080">14</span>
				<span style="COLOR: #000000">
						<img id="Codehighlighter1_409_508_Open_Image" onclick="this.style.display='none'; Codehighlighter1_409_508_Open_Text.style.display='none'; Codehighlighter1_409_508_Closed_Image.style.display='inline'; Codehighlighter1_409_508_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
						<img id="Codehighlighter1_409_508_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_409_508_Closed_Text.style.display='none'; Codehighlighter1_409_508_Open_Image.style.display='inline'; Codehighlighter1_409_508_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> testShouldShowAWeclomeMessageAfterUserLoggedIn() </span>
				<span id="Codehighlighter1_409_508_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.blogjava.net/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_409_508_Open_Text">
						<span style="COLOR: #000000">{<br /></span>
						<span style="COLOR: #008080">15</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    login(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">some guy</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">, </span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">password</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">);<br /></span>
						<span style="COLOR: #008080">16</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    assertTrue(currentPage.isTextPresent(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">Welcome to xxxx</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">));<br /></span>
						<span style="COLOR: #008080">17</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
		</div>
		<p>基本上这只不过是"另一种写法"而已，但是它更好的表达了"用户的行为"，如login代码所示。以及"系统的正确相应"，即currentPage.isTextPresent()。这种是典型的对编译器无意义对人有意义的代码，也就是普遍意义上好的代码。</p>
		<p>3. Creating a DSL base on your test codes</p>
		<p>懂得HTML的QA可以在没有DEV的帮助下使用Selenium FIT mode，然而却不能在没有DEV的帮助下使用Driven Mode。于是最自然也是最fashion的做法，就是在已有的test codes之上提供Testing DSL或者Scripting Language，让FIT mode变得更加FIT。这方面内容是一个更大的主题，以后再详细展开吧。</p>
		<p>4. Hacking Selenium Object to support FIT command</p>
		<p>Selenium FIT mode和RC mode下的命令有些许差异，比如FIT中的assertTextPresent，在RC中变成了isTextPresent。同样还有FIT中最实用的命令clickAndWait，在RC中变成了click和waitForPageToLoad。在RC中使用FIT mode中的命令也非难事，找到com.thoughtworks.selenium.Selenium，添加方法:</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> doCommand(String commmand, String<img src="http://www.blogjava.net/images/dot.gif" /> parameters);</span>
		</div>
		<p>然后在com.thoughtworks.selenium.DefaultSelenium中添加实现:</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #008080">1</span>
				<img id="Codehighlighter1_61_241_Open_Image" onclick="this.style.display='none'; Codehighlighter1_61_241_Open_Text.style.display='none'; Codehighlighter1_61_241_Closed_Image.style.display='inline'; Codehighlighter1_61_241_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
				<img id="Codehighlighter1_61_241_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_61_241_Closed_Text.style.display='none'; Codehighlighter1_61_241_Open_Image.style.display='inline'; Codehighlighter1_61_241_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> doCommand(String commmand, String<img src="http://www.blogjava.net/images/dot.gif" /> parameters) </span>
				<span id="Codehighlighter1_61_241_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.blogjava.net/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_61_241_Open_Text">
						<span style="COLOR: #000000">{<br /></span>
						<span style="COLOR: #008080">2</span>
						<span style="COLOR: #000000">
								<img id="Codehighlighter1_95_104_Open_Image" onclick="this.style.display='none'; Codehighlighter1_95_104_Open_Text.style.display='none'; Codehighlighter1_95_104_Closed_Image.style.display='inline'; Codehighlighter1_95_104_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" />
								<img id="Codehighlighter1_95_104_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_95_104_Closed_Text.style.display='none'; Codehighlighter1_95_104_Open_Image.style.display='inline'; Codehighlighter1_95_104_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />   String[] paras </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">new</span>
						<span style="COLOR: #000000"> String[]</span>
						<span id="Codehighlighter1_95_104_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.blogjava.net/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_95_104_Open_Text">
								<span style="COLOR: #000000">{</span>
								<span style="COLOR: #000000">""</span>
								<span style="COLOR: #000000">,</span>
								<span style="COLOR: #000000">""</span>
								<span style="COLOR: #000000">,</span>
								<span style="COLOR: #000000">""</span>
								<span style="COLOR: #000000">}</span>
						</span>
						<span style="COLOR: #000000">
								<br />
						</span>
						<span style="COLOR: #008080">3</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />   </span>
						<span style="COLOR: #0000ff">for</span>
						<span style="COLOR: #000000"> (</span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> i </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">0</span>
						<span style="COLOR: #000000">; i </span>
						<span style="COLOR: #000000">&lt;</span>
						<span style="COLOR: #000000"> parameters.length </span>
						<span style="COLOR: #000000">&amp;&amp;</span>
						<span style="COLOR: #000000"> i </span>
						<span style="COLOR: #000000">&lt;</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">3</span>
						<span style="COLOR: #000000">; i</span>
						<span style="COLOR: #000000">++</span>
						<span style="COLOR: #000000">)<br /></span>
						<span style="COLOR: #008080">4</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />      paras[i] </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> parameters[i];<br /></span>
						<span style="COLOR: #008080">5</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />   commandProcessor.doCommand(command, paras);<br /></span>
						<span style="COLOR: #008080">6</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
		</div>
		<p>然后试验一下:</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #000000">selenium.doCommand(</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">clickAndWait</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">);</span>
		</div>
		<p>在我们使用纯RC mode之前曾经用过一段中间方案，将rc code转化为fit code来跑(因为rc不支持https)，由于不是真正的rc mode，像isTextPresent之类的方法都没有办法使用，只能使用FIT mode command。因此如果因为一些特殊的原因(https, chrome起不来，hta bug多等等)，你没有办法使用RC mode，但是有希望得到RC可重构的好处，那么这个tricky的技巧倒是不错的选择。</p>
		<p>5. Using chrome and IE hta lanucher to support https<br />6. Run test using different browser lanucher to test browser compatibility</p>
		<p>这两个都是和browser lanucher相关的，Selenium和JWebUnit最大的不同在于它使用真实的浏览器来跑测试，从而可以更加真实地考察系统在不同浏览器中的表现。因此使用不同的浏览器lanucher来运行测试，可以更好测试应用的浏览器兼容性，这对于web 2.0应用而言是很有帮助的。此外，使用rc提供的试验性lanucher，chrome和hta可以解决跨domain测试和https的问题。不过目前hta还是有很多bug的，推荐使用chrome。当然，最希望的还是澳洲的同事可以早日在selenium里提供https支持。<br /></p>
<img src ="http://www.blogjava.net/raimundox/aggbug/61860.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/raimundox/" target="_blank">Raimundox</a> 2006-08-04 21:59 <a href="http://www.blogjava.net/raimundox/archive/2006/08/04/61860.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ANTLR Lexer Tips</title><link>http://www.blogjava.net/raimundox/archive/2006/03/27/37605.html</link><dc:creator>Raimundox</dc:creator><author>Raimundox</author><pubDate>Mon, 27 Mar 2006 06:44:00 GMT</pubDate><guid>http://www.blogjava.net/raimundox/archive/2006/03/27/37605.html</guid><wfw:comment>http://www.blogjava.net/raimundox/comments/37605.html</wfw:comment><comments>http://www.blogjava.net/raimundox/archive/2006/03/27/37605.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/raimundox/comments/commentRss/37605.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/raimundox/services/trackbacks/37605.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 参加ThoughtWorks University的一个来月没啥事情，闲了写写compiler玩。发现Lexer部分比较基础也比较常用，有很多相似的东西，每次都要写一遍也太麻烦了，下面是我按着JSL写的一个common java-like lexer，对于大多数接近java语法的语言估计是够用了。BTW：这个Lexer定义是TDD出来，以通过测试为要务，可能可读性不太强。1.WhiteSpaceC...&nbsp;&nbsp;<a href='http://www.blogjava.net/raimundox/archive/2006/03/27/37605.html'>阅读全文</a><img src ="http://www.blogjava.net/raimundox/aggbug/37605.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/raimundox/" target="_blank">Raimundox</a> 2006-03-27 14:44 <a href="http://www.blogjava.net/raimundox/archive/2006/03/27/37605.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>A Patch for Ruby Watir Test Framework</title><link>http://www.blogjava.net/raimundox/archive/2006/01/11/27549.html</link><dc:creator>Raimundox</dc:creator><author>Raimundox</author><pubDate>Wed, 11 Jan 2006 03:30:00 GMT</pubDate><guid>http://www.blogjava.net/raimundox/archive/2006/01/11/27549.html</guid><wfw:comment>http://www.blogjava.net/raimundox/comments/27549.html</wfw:comment><comments>http://www.blogjava.net/raimundox/archive/2006/01/11/27549.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/raimundox/comments/commentRss/27549.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/raimundox/services/trackbacks/27549.html</trackback:ping><description><![CDATA[昨天发现了Ruby Watir里的一个小问题，没有办法在Text Field里输入中文。虽然已经hack了，但是还是不太爽，G.H.Hardy说：<br><br>Beauty is the first 
test: there is no permanent place in this world for ugly mathematics. <br><br>感动了我好久。现在换个说法：<br><br>Beauty is the first 
test: there is no permanent place in this world for ugly hack code. <br><br>这个问题也不太难出理，ruby作为C的front interface在字符串处理上有很深的C的痕迹，嗯，10年前我还是个C程序员嘛，按照从前的做法区分ASCII码。<br><br><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 128, 128);">1</span>&nbsp;<span style="color: rgb(0, 0, 0);">def characters_in(value)&nbsp;<br></span><span style="color: rgb(0, 128, 128);">2</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;index&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">3</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">while</span><span style="color: rgb(0, 0, 0);">&nbsp;index&nbsp;</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">&nbsp;value.length&nbsp;<br></span><span style="color: rgb(0, 128, 128);">4</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;len&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;value[index]&nbsp;</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">128</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">?</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">2</span><span style="color: rgb(0, 0, 0);">&nbsp;:&nbsp;</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">5</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;yield&nbsp;value[index,&nbsp;len]<br></span><span style="color: rgb(0, 128, 128);">6</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;index&nbsp;</span><span style="color: rgb(0, 0, 0);">+=</span><span style="color: rgb(0, 0, 0);">&nbsp;len<br></span><span style="color: rgb(0, 128, 128);">7</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;end&nbsp;<br></span><span style="color: rgb(0, 128, 128);">8</span>&nbsp;<span style="color: rgb(0, 0, 0);">end</span></div><br>把TextField里的doKeyPress改一下：<br><br><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 128, 128);">1</span>&nbsp;<span style="color: rgb(0, 0, 0);">characters_in(value)&nbsp;{</span><span style="color: rgb(0, 0, 0);">|</span><span style="color: rgb(0, 0, 0);">c</span><span style="color: rgb(0, 0, 0);">|</span><span style="color: rgb(0, 0, 0);">&nbsp;<br></span><span style="color: rgb(0, 128, 128);">2</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;sleep&nbsp;@ieController.typingspeed<br></span><span style="color: rgb(0, 128, 128);">3</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;@o.value&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;@o.value.to_s&nbsp;</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);">&nbsp;c<br></span><span style="color: rgb(0, 128, 128);">4</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;fire_key_events}</span></div><br>搞定！但是还是很丑，直接把别人的code改了，contributing to eclipse里说要contribute不要随便change别人的代码。好吧，好在ruby扩展起来也不难：<br><br><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 128, 128);">&nbsp;1</span>&nbsp;<span style="color: rgb(0, 0, 0);">require&nbsp;</span><span style="color: rgb(0, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">Watir</span><span style="color: rgb(0, 0, 0);">'</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">&nbsp;2</span>&nbsp;<span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">&nbsp;3</span>&nbsp;<span style="color: rgb(0, 0, 0);">module&nbsp;Watir<br></span><span style="color: rgb(0, 128, 128);">&nbsp;4</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;module&nbsp;Cn<br></span><span style="color: rgb(0, 128, 128);">&nbsp;5</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);">&nbsp;IE&nbsp;</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">Watir::IE<br></span><span style="color: rgb(0, 128, 128);">&nbsp;6</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;text_field(how&nbsp;,&nbsp;what</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">nil)<br></span><span style="color: rgb(0, 128, 128);">&nbsp;7</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);">&nbsp;TextField.</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">(self,&nbsp;how,&nbsp;what)<br></span><span style="color: rgb(0, 128, 128);">&nbsp;8</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br></span><span style="color: rgb(0, 128, 128);">&nbsp;9</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;end<br></span><span style="color: rgb(0, 128, 128);">10</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="color: rgb(0, 128, 128);">11</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);">&nbsp;TextField&nbsp;</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">&nbsp;Watir::TextField<br></span><span style="color: rgb(0, 128, 128);">12</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;doKeyPress(&nbsp;value&nbsp;)<br></span><span style="color: rgb(0, 128, 128);">13</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin<br></span><span style="color: rgb(0, 128, 128);">14</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxLength&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;@o.maxLength<br></span><span style="color: rgb(0, 128, 128);">15</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">&nbsp;value.length&nbsp;</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">&nbsp;maxLength<br></span><span style="color: rgb(0, 128, 128);">16</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;suppliedValue[</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">&nbsp;..&nbsp;maxLength&nbsp;]<br></span><span style="color: rgb(0, 128, 128);">17</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@ieController.log&nbsp;</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">&nbsp;Supplied&nbsp;string&nbsp;is&nbsp;#{suppliedValue.length}&nbsp;chars,&nbsp;which&nbsp;exceeds&nbsp;the&nbsp;max&nbsp;length&nbsp;(#{maxLength})&nbsp;of&nbsp;the&nbsp;field.&nbsp;Using&nbsp;value:&nbsp;#{value}</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">18</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br></span><span style="color: rgb(0, 128, 128);">19</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rescue<br></span><span style="color: rgb(0, 128, 128);">20</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;probably&nbsp;a&nbsp;text&nbsp;area&nbsp;</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">&nbsp;so&nbsp;it&nbsp;doesnt&nbsp;have&nbsp;a&nbsp;max&nbsp;Length<br></span><span style="color: rgb(0, 128, 128);">21</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxLength&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">22</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br></span><span style="color: rgb(0, 128, 128);">23</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="color: rgb(0, 128, 128);">24</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Cn.characters_in(value)&nbsp;{</span><span style="color: rgb(0, 0, 0);">|</span><span style="color: rgb(0, 0, 0);">c</span><span style="color: rgb(0, 0, 0);">|</span><span style="color: rgb(0, 0, 0);">&nbsp;<br></span><span style="color: rgb(0, 128, 128);">25</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep&nbsp;@ieController.typingspeed<br></span><span style="color: rgb(0, 128, 128);">26</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@o.value&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;@o.value.to_s&nbsp;</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);">&nbsp;c<br></span><span style="color: rgb(0, 128, 128);">27</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fire_key_events}<br></span><span style="color: rgb(0, 128, 128);">28</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br></span><span style="color: rgb(0, 128, 128);">29</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;end<br></span><span style="color: rgb(0, 128, 128);">30</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="color: rgb(0, 128, 128);">31</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;Cn.characters_in(value)&nbsp;<br></span><span style="color: rgb(0, 128, 128);">32</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;index&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">33</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">while</span><span style="color: rgb(0, 0, 0);">&nbsp;index&nbsp;</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">&nbsp;value.length&nbsp;<br></span><span style="color: rgb(0, 128, 128);">34</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;len&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;value[index]&nbsp;</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">128</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">?</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">2</span><span style="color: rgb(0, 0, 0);">&nbsp;:&nbsp;</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">35</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;yield&nbsp;value[index,&nbsp;len]<br></span><span style="color: rgb(0, 128, 128);">36</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;index&nbsp;</span><span style="color: rgb(0, 0, 0);">+=</span><span style="color: rgb(0, 0, 0);">&nbsp;len<br></span><span style="color: rgb(0, 128, 128);">37</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end&nbsp;<br></span><span style="color: rgb(0, 128, 128);">38</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;end<br></span><span style="color: rgb(0, 128, 128);">39</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;end<br></span><span style="color: rgb(0, 128, 128);">40</span>&nbsp;<span style="color: rgb(0, 0, 0);">end</span></div><br>测试一下：<br><br><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">require&nbsp;</span><span style="color: rgb(0, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">watir-cn</span><span style="color: rgb(0, 0, 0);">'</span><span style="color: rgb(0, 0, 0);"><br><br>ie&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;Watir::Cn::IE.start(</span><span style="color: rgb(0, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">http://www.google.com</span><span style="color: rgb(0, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">)<br>ie.text_field(:name,&nbsp;</span><span style="color: rgb(0, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">q</span><span style="color: rgb(0, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">).set(</span><span style="color: rgb(0, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">Ruby&nbsp;Watir&nbsp;功能测试</span><span style="color: rgb(0, 0, 0);">'</span></div><br>成功。最后一步是贡献社区，直接登到rubyforge，找到Watir然后submit了两个patch：一个直接修改watir库的一个是独立的watir-cn的。推荐大家使用第二个的patch。地址在：<a href="http://rubyforge.org/tracker/index.php?func=detail&amp;aid=3232&amp;group_id=104&amp;atid=489">http://rubyforge.org/tracker/index.php?func=detail&amp;aid=3232&amp;group_id=104&amp;atid=489</a></span><br><img src ="http://www.blogjava.net/raimundox/aggbug/27549.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/raimundox/" target="_blank">Raimundox</a> 2006-01-11 11:30 <a href="http://www.blogjava.net/raimundox/archive/2006/01/11/27549.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>A Day of Two Pragmatic Programmers'  Life</title><link>http://www.blogjava.net/raimundox/archive/2006/01/10/27469.html</link><dc:creator>Raimundox</dc:creator><author>Raimundox</author><pubDate>Tue, 10 Jan 2006 13:30:00 GMT</pubDate><guid>http://www.blogjava.net/raimundox/archive/2006/01/10/27469.html</guid><wfw:comment>http://www.blogjava.net/raimundox/comments/27469.html</wfw:comment><comments>http://www.blogjava.net/raimundox/archive/2006/01/10/27469.html#Feedback</comments><slash:comments>8</slash:comments><wfw:commentRss>http://www.blogjava.net/raimundox/comments/commentRss/27469.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/raimundox/services/trackbacks/27469.html</trackback:ping><description><![CDATA[今天我和WPC被迫派给了一个很nonsense的活，客户给了我们两份名单，让我们对照我们SSO中的用户数据做一下数据维护，如果有的用户在SSO中没有就加进来；要是SSO中有，看一下OA里有没有，如果OA里没有写一个列表让OA的同志们去维护数据。本来是一个很枯燥的活，好在WPC和我都是pragmatic programers，于是生活变得有乐趣多了。<BR>解决这个问题最直接的做法，就是login到SSO平台上，然后一个用户一个用户的search，search完了再用OA Admin登陆查OA帐户。我们是pragmatic programmer嘛，这么繁琐的活动自然写程序搞定它。自然浮现两个选择：Ruby Watri，还有就是产自俺们公司的Selenium Script。<BR>上来先用Ruby Watri，这个东西好啊，简单啊。WPC找了一个以前写的example, 我照着改了一个用户的search，然后扩展：
<DIV style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><SPAN style="COLOR: rgb(0,128,128)">&nbsp;1</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">#&nbsp;login&nbsp;in&nbsp;as&nbsp;sso&nbsp;admin<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;2</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">ie&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;Watir::IE.start(sso_login_url)<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;3</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">ie.text_field(:name,</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">username</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">).set(sso_admin_user)<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;4</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">ie.text_field(:name,</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">password</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">).set(sso_admin_pass)<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;5</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">ie.button(:value,&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">登录</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">).click<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;6</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)"><BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;7</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">#&nbsp;search&nbsp;user<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;8</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">ie&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;Watir::IE.start(sso_search_url)<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;9</SPAN> <SPAN style="COLOR: rgb(0,0,0)">ie.text_field(:name,&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">userName).set('张三')</SPAN><SPAN style="COLOR: rgb(0,0,0)"></SPAN><SPAN style="COLOR: rgb(0,0,0)"><BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">10</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)"></SPAN><SPAN style="COLOR: rgb(0,0,0)">ie.button(:value,&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">查找</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">).click</SPAN></DIV><BR>跑到command line run一把，ruby login.rb，然后一个古怪的事情出现了<BR>
<DIV style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><SPAN style="COLOR: rgb(0,0,0)">ie.text_field(:name,&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">userName).set('张三')</SPAN></DIV>userName输入框highlight了一下，然后没有字...难道是编码问题？换了encoding重新save了一把，结果一样。郁闷...于是我和WPC想法是...Ruby中文有问题，不管了时间紧迫，换Selenium Test，自家的东西嘛。但是Selenium的Script是HTML-based的，写起来太麻烦。我们是pragmatic programmer嘛，这么繁琐的活动自然写程序搞定它。于是我来搞一个ScriptGenerator，WPC同志搞script template。一搞template WPC同志就比较兴奋，大喊:velocity！ velocity！哎，我机器上没有velocity的library，于是我决定pragmatic一把，直接writer output。找了一个Selenume Script Demo，在每行前面加上aaaa,每行末尾加上bbb，然后ctrl + f,aaa-&gt;writer.write(" bbb-&gt;"); 改几个"，introduce parameter, extract method, compose method飞快地重构之，一个hard code的generator引擎诞生了。WPC还在调template，我看了一下代码，蛮ugly的，refactory之：<BR>
<DIV style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><SPAN style="COLOR: rgb(0,128,128)">&nbsp;1</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">private</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">static</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;String&nbsp;scriptTemplate;<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;2</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)"><BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;3</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">public</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">static</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">void</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;readScriptTemplate(String&nbsp;templateName)&nbsp;{<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;4</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BufferedReader&nbsp;reader&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">null</SPAN><SPAN style="COLOR: rgb(0,0,0)">;<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;5</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">try</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;{<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;6</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;reader&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">new</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;BufferedReader(</SPAN><SPAN style="COLOR: rgb(0,0,255)">new</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;FileReader(templateName));<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;7</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;line&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">null</SPAN><SPAN style="COLOR: rgb(0,0,0)">;<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;8</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;StringBuffer&nbsp;template&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">new</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;StringBuffer();<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;9</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">while</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;((line&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;reader.readLine())&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">!=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">null</SPAN><SPAN style="COLOR: rgb(0,0,0)">)<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">10</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;template.append(line).append(</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">\n</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">);<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">11</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;scriptTemplate&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;template.toString();<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">12</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">catch</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;(IOException&nbsp;e)&nbsp;{<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">13</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)"><BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">14</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">finally</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;{<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">15</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">if</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;(reader&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">!=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">null</SPAN><SPAN style="COLOR: rgb(0,0,0)">)<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">16</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">try</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;{<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">17</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;reader.close();<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">18</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">catch</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;(IOException&nbsp;e)&nbsp;{<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">19</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">20</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">21</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;}<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">22</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)"><BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">23</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">public</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">static</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">void</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;generatedScriptForUser(String&nbsp;path,&nbsp;String&nbsp;name)&nbsp;{<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">24</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Writer&nbsp;writer&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">null</SPAN><SPAN style="COLOR: rgb(0,0,0)">;<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">25</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">try</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;{<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">26</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writer&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">new</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;BufferedWriter(</SPAN><SPAN style="COLOR: rgb(0,0,255)">new</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;FileWriter(path&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">+</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">/</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">+</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;name<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">27</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">+</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">.html</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">));<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">28</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writer.write(scriptTemplate<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">29</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.replaceAll(</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">\\$\\$userName\\$\\$</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">,&nbsp;name));<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">30</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">catch</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;(IOException&nbsp;e)&nbsp;{<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">31</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">32</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">finally</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;{<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">33</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">if</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;(writer&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">!=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">null</SPAN><SPAN style="COLOR: rgb(0,0,0)">)<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">34</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">try</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;{<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">35</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writer.close();<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">36</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">catch</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;(IOException&nbsp;e)&nbsp;{<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">37</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">38</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">39</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)"><BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">40</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;}</SPAN></DIV><BR>一下子少了无数代码，爽多了。然后wpc也搞好了template，按模版文件一generating，几十个selenium test script就出现了。嗯，write program that write program，有够pragmatic。<BR><BR>写了一个Test Suite，放到改一下Selenium Runner下跑一下又傻眼了。Selenium做的Functional Test，一般假定和被测的应用在一个URL base里，因此这样local“测”remoting就不太好，而且我们又是一个安全平台，URL base做安全基准的。一下就所有测试就crackdown在这里了。郁闷啊...<BR>Selenium文档，发现可以用driver来adpater local和remoting的环境，问题是这个drvier要自己写...郁闷...<BR>WPC在firefox上装了一个Selenium Recorder的plug in可以记录web page actions，然后replay。他发现这个东西能绕过Selenium的限制，于是决定看看他怎么实现的，找到code一看...原来是把selenium runner hack了...用javascript把url base生生的给改了...WPC说好啊，我们写一个Firefox Selenium Recorder Plugin的plug in吧，让他从一个目录里自动load script...然后WPC开始玩firefox plugin.<BR><BR>我决得我还是看看Ruby的中文支持吧，找来找去都没有说Ruby的中文有问题的，后来发现一个老大测了一下Ruby的中文字符串，说没问题。我忘了这个老大的URL了找到再补上。代码上看起来似乎也没什么问题。于是我怀疑是Watri的问题，看Watri的代码，发现Watri的设计思路就是为了模拟人的录入，然后找到这样的代码：<BR>
<DIV style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><SPAN style="COLOR: rgb(0,0,0)">def&nbsp;doKeyPress(value)<BR><BR><IMG src="http://www.blogjava.net/images/dot.gif"><BR><BR></SPAN><SPAN style="COLOR: rgb(0,0,255)">for</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;i&nbsp;in&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">0</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;..&nbsp;value.length</SPAN><SPAN style="COLOR: rgb(0,0,0)">-</SPAN><SPAN style="COLOR: rgb(0,0,0)">1</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp; sleep&nbsp;@ieController.typingspeed&nbsp;&nbsp;&nbsp;#&nbsp;typing&nbsp;speed<BR>&nbsp;&nbsp; c&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;value[i,</SPAN><SPAN style="COLOR: rgb(0,0,0)">1</SPAN><SPAN style="COLOR: rgb(0,0,0)">]<BR>&nbsp;&nbsp; #@ieController.log&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;adding&nbsp;c.chr&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">+</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;c&nbsp;&nbsp;#.chr.to_s<BR>&nbsp;&nbsp; @o.value&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;@o.value.to_s&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">+</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;c&nbsp;&nbsp;&nbsp;#c.chr<BR>&nbsp;&nbsp; fire_key_events<BR>end<BR><BR><IMG src="http://www.blogjava.net/images/dot.gif"><BR><BR>end</SPAN></DIV>根据设定的延时模拟人敲击键盘。每一个间隔用String slice来输入。于是我试验了一下ruby的中文字符串切片：<BR><BR>
<DIV style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><SPAN style="COLOR: rgb(0,128,128)">1</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">value&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">哈哈</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)"><BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">2</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)"></SPAN><SPAN style="COLOR: rgb(0,0,255)">for</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;i&nbsp;in&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">0</SPAN><SPAN style="COLOR: rgb(0,0,0)">..value.length</SPAN><SPAN style="COLOR: rgb(0,0,0)">-</SPAN><SPAN style="COLOR: rgb(0,0,0)">1</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">3</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;puts&nbsp;value[i,</SPAN><SPAN style="COLOR: rgb(0,0,0)">1</SPAN><SPAN style="COLOR: rgb(0,0,0)">]<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">4</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">end</SPAN></DIV>Ruby果然瞎菜了...value.length是4，每一个切片都是空...啊~~~~天啊，8bit char...C的时代啊。找到了问题就好办了，我权衡了fix watri unicode和直接hack它，最后我选择直接hack它，方法简单：<BR><BR>
<DIV style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><SPAN style="COLOR: rgb(0,128,128)">&nbsp;1</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,255)">if</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;@ieController.typingspeed&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">!=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">-</SPAN><SPAN style="COLOR: rgb(0,0,0)">1</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;2</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp; </SPAN><SPAN style="COLOR: rgb(0,0,255)">for</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;i&nbsp;in&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">0</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;..&nbsp;value.length</SPAN><SPAN style="COLOR: rgb(0,0,0)">-</SPAN><SPAN style="COLOR: rgb(0,0,0)">1</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;3</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp; sleep&nbsp;@ieController.typingspeed&nbsp;&nbsp;&nbsp;#&nbsp;typing&nbsp;speed<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;4</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp; c&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;value[i,</SPAN><SPAN style="COLOR: rgb(0,0,0)">1</SPAN><SPAN style="COLOR: rgb(0,0,0)">]<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;5</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp; #@ieController.log&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;adding&nbsp;c.chr&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">+</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;c&nbsp;&nbsp;#.chr.to_s<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;6</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp; @o.value&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;@o.value.to_s&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">+</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;c&nbsp;&nbsp;&nbsp;#c.chr<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;7</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp; fire_key_events<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;8</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp; end<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;9</SPAN> <SPAN style="COLOR: rgb(0,0,0)"></SPAN><SPAN style="COLOR: rgb(0,0,255)">else</SPAN><SPAN style="COLOR: rgb(0,0,0)"><BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">10</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp; @o.value&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;value<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">11</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp; fire_key_events<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">12</SPAN> <SPAN style="COLOR: rgb(0,0,0)">end</SPAN></DIV><BR>然后测试一下：<BR>
<DIV style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><SPAN style="COLOR: rgb(0,128,128)">1</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">require&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">'</SPAN><SPAN style="COLOR: rgb(0,0,0)">Watir</SPAN><SPAN style="COLOR: rgb(0,0,0)">'</SPAN><SPAN style="COLOR: rgb(0,0,0)"><BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">2</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)"><BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">3</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">ie&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;Watir::IE.start(</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">http://www.google.com</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">)<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">4</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">ie.typingspeed&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">-</SPAN><SPAN style="COLOR: rgb(0,0,0)">1</SPAN><SPAN style="COLOR: rgb(0,0,0)"><BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">5</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">ie.text_field(:name,&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">q</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">).set(</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">哈哈</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">)</SPAN></DIV><BR>搞定。于是准备改Ruby脚本，这个时候客户下班了，我们决定明天继续，一共用时2小时...<BR><BR>最后说一下需求，一共有多少数据呢？70条...如果pair录入的话，大约40-50分钟吧<BR><BR>结论:<BR><BR>1.Pragmatic Programmer都是很懒的，重复5次的工作都回用代码来写。<BR>2.Pragmatic Programmer都是很有好奇心的，太多的重复性劳动只能分散他们的注意力，不知道会搞出什么了，我估计我要没有hack Watri，WPC已经开始写Firefox plugin了。<BR>3.Pragmatic Programmer都是“古程序员”，写程序操纵计算机是很有乐趣的。<BR>4.比一个Pragmatic Programmer更能折腾的是两个Pragmatic Programmer...<BR><BR><BR><img src ="http://www.blogjava.net/raimundox/aggbug/27469.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/raimundox/" target="_blank">Raimundox</a> 2006-01-10 21:30 <a href="http://www.blogjava.net/raimundox/archive/2006/01/10/27469.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>丧钟为谁鸣?(4)</title><link>http://www.blogjava.net/raimundox/archive/2005/12/21/24957.html</link><dc:creator>Raimundox</dc:creator><author>Raimundox</author><pubDate>Wed, 21 Dec 2005 07:51:00 GMT</pubDate><guid>http://www.blogjava.net/raimundox/archive/2005/12/21/24957.html</guid><wfw:comment>http://www.blogjava.net/raimundox/comments/24957.html</wfw:comment><comments>http://www.blogjava.net/raimundox/archive/2005/12/21/24957.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/raimundox/comments/commentRss/24957.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/raimundox/services/trackbacks/24957.html</trackback:ping><description><![CDATA[<P>第3. 一切皆对象和面向对象的理论基础</P>
<P>老庄是反对一切皆对象的，而TrustNo1在javaeye的一篇帖子上说:</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">第一，我可以很负责的说,OO的，70年代成型，80年代在理论基础上就给人毙掉。从这种意义上说不是OO死不死的问题，而是OO还活着么？当然理论基础给人毙掉，不是说没有用。</SPAN></DIV>
<P>我先说面向对象的理论基础的问题，至于一切皆对象稍后再表。<BR><BR>所谓面向对象的理论基础其实是没有的，原因很简单，面向对象根本就不是一种计算模型。在第一次软件危机的那个时代，对与计算机的非数值计算应用的讨论以及对于可计算性问题的研究和发展，大抵确立了几种主流的计算模型：递归函数类，图灵机，Lambda演算，Horn子句，Post系统等等。<BR><BR>其中递归函数类是可计算性问题的数学解释;图灵机是图灵解决可计算问题的时候所设计的装置，其后成为计算机的装置模型，与图灵机相关的形式语言和自动机成为了命令式语言的理论基础;lambda演算成为了函数式语言的理论基础;Horn子句是prolog这类逻辑语言的理论基础。但是我们惊讶的发现，面向对象没有计算模型的理论基础，换而言之，面向对象根本就不是从可计算性的研究上发展过来的，那么面向对象的理论基础的价值本身就不大。</P>
<P>所以我很奇怪的一个问题就是TrustNo1所谓的面向对象在80年代理论基础上给人毙掉的说法是从何而来的？既然面向对象本质上不是一种计算模型，那么它大抵上只能归结为一种应用技术，应用技术自然可以从各种不同的领域里得到相似的应用，那么毙掉的理论基础所指的又是什么呢？甚怪之。</P>
<P>既然面向对象不是一个计算模型，那么我们可以从不同的角度推断出OO的各种形态，老庄已经出给了从ADT引出OO的问题以及例子，我就不罗嗦了，我给一个从Functional Programming出来的例子，其实就是SICP里的Data as Procedure。</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">(define&nbsp;(make</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #000000">user&nbsp;name&nbsp;age&nbsp;sex)<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;(define&nbsp;(dispatch&nbsp;message)<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond&nbsp;((eq</SPAN><SPAN style="COLOR: #000000">?</SPAN><SPAN style="COLOR: #000000">&nbsp;message&nbsp;</SPAN><SPAN style="COLOR: #000000">'</SPAN><SPAN style="COLOR: #000000">getName)&nbsp;name)</SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;((eq</SPAN><SPAN style="COLOR: #000000">?</SPAN><SPAN style="COLOR: #000000">&nbsp;message&nbsp;</SPAN><SPAN style="COLOR: #000000">'</SPAN><SPAN style="COLOR: #000000">getAge)&nbsp;age)</SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;((eq</SPAN><SPAN style="COLOR: #000000">?</SPAN><SPAN style="COLOR: #000000">&nbsp;message&nbsp;</SPAN><SPAN style="COLOR: #000000">'</SPAN><SPAN style="COLOR: #000000">getSex)&nbsp;sex))</SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</SPAN><SPAN style="COLOR: #0000ff">else</SPAN><SPAN style="COLOR: #000000">&nbsp;(error&nbsp;</SPAN><SPAN style="COLOR: #000000">'</SPAN><SPAN style="COLOR: #000000">messageNotUnderstand))))</SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;dispatch)</SPAN></DIV>
<P>然后我们就可以</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">(define&nbsp;vincent&nbsp;(make</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #000000">user&nbsp;</SPAN><SPAN style="COLOR: #000000">'</SPAN><SPAN style="COLOR: #000000">Vincent&nbsp;24&nbsp;</SPAN><SPAN style="COLOR: #000000">'</SPAN><SPAN style="COLOR: #000000">Male))<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>(vincent&nbsp;</SPAN><SPAN style="COLOR: #000000">'</SPAN><SPAN style="COLOR: #000000">getName)</SPAN></DIV>
<P>自然的，如果我调用</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">(vincent&nbsp;</SPAN><SPAN style="COLOR: #000000">'</SPAN><SPAN style="COLOR: #000000">sayHi)</SPAN></DIV>
<P>会得到一个messageNotUnderstand的runtime错误，这就是一个很自然dyanmic type的对象封装，最早的面向对象系统Smalltalk和CLOS基本上都是这个路子，于是有一个问题，为什么最早的面向对象系统都是dyanmic type？这里就跟lambda演算有关了。</P>
<P>lambda演算这个计算模型根本的一个假设就是，对于任何一个定义良好的数学函数，我都可以使用lambda抽象来表述他的求值，因此无论是什么东西你能够构造lambda抽象的话，我就能计算。这个地方东西很多，大家可以找找lambda演算相关的资料，这里我说三件事(由于lambda太难输入，我用scheme程序代替，然后由于alpha变化，beta规约和eta规约我也用scheme伪码来模拟。)</P>
<P>第一个是数值的表述，其实这个很简单，不考虑丘奇代数的系统的话，我们可以把数值表示成单值函数:</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">(define&nbsp;one&nbsp;(lambda&nbsp;(x)&nbsp;</SPAN><SPAN style="COLOR: #000000">1</SPAN><SPAN style="COLOR: #000000">))</SPAN></DIV>
<P>这个东西无论给什么x都返回1，然后根据lambda演算里的alpha变换，这个lambda抽象等价于数值1。因此，对于所有的数值，我们可以按lambda演算处理。</P>
<P>第二个是bool的表达，也就是如何逻辑进行lambda抽象，下面我直接给出了，缺省认为大家都看了SICP，对Scheme也颇有心得。</P>
<P></P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">(define&nbsp;</SPAN><SPAN style="COLOR: #0000ff">true</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">&nbsp;(lambda&nbsp;(x&nbsp;y)&nbsp;x))&nbsp;;;;这个函数也叫select</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #000000">first<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>(define&nbsp;</SPAN><SPAN style="COLOR: #0000ff">false</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">&nbsp;(lambda&nbsp;(x&nbsp;y)&nbsp;x));;;这个函数也叫select</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #000000">second<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>(define&nbsp;</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">&nbsp;(lambda&nbsp;(conditon&nbsp;</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #0000ff">true</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #0000ff">false</SPAN><SPAN style="COLOR: #000000">)&nbsp;(condition&nbsp;</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #0000ff">true</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #0000ff">false</SPAN><SPAN style="COLOR: #000000">)))</SPAN></DIV>
<P>然后我就可以做一个测试</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">true</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">3</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">4</SPAN><SPAN style="COLOR: #000000">)<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">3</SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>(</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">false</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">3</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">4</SPAN><SPAN style="COLOR: #000000">)<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">4</SPAN></DIV>
<P>因此，对于所有bool我们可以按lambda演算来处理</P>
<P>第三个是自定义类型，这里我们还是先看一个Lisp里的例子，序对。</P>
<P></P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif"