今天我和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...