今天我和WPC被迫派给了一个很nonsense的活,客户给了我们两份名单,让我们对照我们SSO中的用户数据做一下数据维护,如果有的用户在SSO中没有就加进来;要是SSO中有,看一下OA里有没有,如果OA里没有写一个列表让OA的同志们去维护数据。本来是一个很枯燥的活,好在WPC和我都是pragmatic programers,于是生活变得有乐趣多了。
解决这个问题最直接的做法,就是login到SSO平台上,然后一个用户一个用户的search,search完了再用OA Admin登陆查OA帐户。我们是pragmatic programmer嘛,这么繁琐的活动自然写程序搞定它。自然浮现两个选择:Ruby Watri,还有就是产自俺们公司的Selenium Script。
上来先用Ruby Watri,这个东西好啊,简单啊。WPC找了一个以前写的example, 我照着改了一个用户的search,然后扩展:
1 # login in as sso admin
2 ie = Watir::IE.start(sso_login_url)
3 ie.text_field(:name,"username").set(sso_admin_user)
4 ie.text_field(:name,"password").set(sso_admin_pass)
5 ie.button(:value, "登录").click
6
7 # search user
8 ie = Watir::IE.start(sso_search_url)
9 ie.text_field(:name, "userName).set('张三')
10 ie.button(:value, "查找").click
跑到command line run一把,ruby login.rb,然后一个古怪的事情出现了
ie.text_field(:name, "userName).set('张三')
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->writer.write(" bbb->"); 改几个",introduce parameter, extract method, compose method飞快地重构之,一个hard code的generator引擎诞生了。WPC还在调template,我看了一下代码,蛮ugly的,refactory之:
1 private static String scriptTemplate;
2
3 public static void readScriptTemplate(String templateName) {
4 BufferedReader reader = null;
5 try {
6 reader = new BufferedReader(new FileReader(templateName));
7 String line = null;
8 StringBuffer template = new StringBuffer();
9 while ((line = reader.readLine()) != null)
10 template.append(line).append("\n");
11 scriptTemplate = template.toString();
12 } catch (IOException e) {
13
14 } finally {
15 if (reader != null)
16 try {
17 reader.close();
18 } catch (IOException e) {
19 }
20 }
21 }
22
23 public static void generatedScriptForUser(String path, String name) {
24 Writer writer = null;
25 try {
26 writer = new BufferedWriter(new FileWriter(path + "/" + name
27 + ".html"));
28 writer.write(scriptTemplate
29 .replaceAll("\\$\\$userName\\$\\$", name));
30 } catch (IOException e) {
31 e.printStackTrace();
32 } finally {
33 if (writer != null)
34 try {
35 writer.close();
36 } catch (IOException e) {
37 }
38 }
39
40 }
一下子少了无数代码,爽多了。然后wpc也搞好了template,按模版文件一generating,几十个selenium test script就出现了。嗯,write program that write program,有够pragmatic。
写了一个Test Suite,放到改一下Selenium Runner下跑一下又傻眼了。Selenium做的Functional Test,一般假定和被测的应用在一个URL base里,因此这样local“测”remoting就不太好,而且我们又是一个安全平台,URL base做安全基准的。一下就所有测试就crackdown在这里了。郁闷啊...
Selenium文档,发现可以用driver来adpater local和remoting的环境,问题是这个drvier要自己写...郁闷...
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.
我决得我还是看看Ruby的中文支持吧,找来找去都没有说Ruby的中文有问题的,后来发现一个老大测了一下Ruby的中文字符串,说没问题。我忘了这个老大的URL了找到再补上。代码上看起来似乎也没什么问题。于是我怀疑是Watri的问题,看Watri的代码,发现Watri的设计思路就是为了模拟人的录入,然后找到这样的代码:
def doKeyPress(value)
for i in 0 .. value.length-1
sleep @ieController.typingspeed # typing speed
c = value[i,1]
#@ieController.log " adding c.chr " + c #.chr.to_s
@o.value = @o.value.to_s + c #c.chr
fire_key_events
end
end 根据设定的延时模拟人敲击键盘。每一个间隔用String slice来输入。于是我试验了一下ruby的中文字符串切片:
1 value = "哈哈"
2 for i in 0..value.length-1
3 puts value[i,1]
4 end
Ruby果然瞎菜了...value.length是4,每一个切片都是空...啊~~~~天啊,8bit char...C的时代啊。找到了问题就好办了,我权衡了fix watri unicode和直接hack它,最后我选择直接hack它,方法简单:
1 if @ieController.typingspeed != -1
2 for i in 0 .. value.length-1
3 sleep @ieController.typingspeed # typing speed
4 c = value[i,1]
5 #@ieController.log " adding c.chr " + c #.chr.to_s
6 @o.value = @o.value.to_s + c #c.chr
7 fire_key_events
8 end
9 else
10 @o.value = value
11 fire_key_events
12 end
然后测试一下:
1 require 'Watir'
2
3 ie = Watir::IE.start("http://www.google.com")
4 ie.typingspeed = -1
5 ie.text_field(:name, "q").set("哈哈")
搞定。于是准备改Ruby脚本,这个时候客户下班了,我们决定明天继续,一共用时2小时...
最后说一下需求,一共有多少数据呢?70条...如果pair录入的话,大约40-50分钟吧
结论:
1.Pragmatic Programmer都是很懒的,重复5次的工作都回用代码来写。
2.Pragmatic Programmer都是很有好奇心的,太多的重复性劳动只能分散他们的注意力,不知道会搞出什么了,我估计我要没有hack Watri,WPC已经开始写Firefox plugin了。
3.Pragmatic Programmer都是“古程序员”,写程序操纵计算机是很有乐趣的。
4.比一个Pragmatic Programmer更能折腾的是两个Pragmatic Programmer...