剛亡弱存

聖人不死,大盜不止

Watir-Webdriver 一些常規測試的實現方法(下)

Headless

headless Gem 軟體包是一個 Ruby 版本的 Xvfb 包裝器,可以輕易地在一臺未知品牌的 Linux 計算機上運行圖形化程式(例如:網頁瀏覽器程式)。此 Gem 軟體包可以優秀地利用瀏覽器進行 headless Watir-WebDriver 測試任務(簡而言之,就是一個 Linux 向軟體包)。

例程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 引用兩個軟體包
require 'watir-webdriver'
require 'headless'

# 創建并展開 headless 環境
headless = Headless.new
headless.start

# 進行常規的測試工作
b = Watir::Browser.start 'www.google.com'
puts b.title
b.close

# 销毁 headless 環境
headless.destroy

Cucumber 應用例程

需要將下面的代碼添加到 env.rb 档案中:

1
2
3
4
5
6
7
8
9
10
if ENV['HEADLESS']
  require 'headless'

  headless = Headless.new
  headless.start

  at_exit do
    headless.destroy
  end
end

頁面性能測量

Watir-WebDriver-Performance Gem 軟體包致力於爲 Watir-WebDriver 測試提供一套基於 W3C 頁面性能標準 的頁面瀏覽響應統計的方法集合。此套件用來捕獲測量頁面響應非常好用,也非常直接有效。但當前此套件僅能工作於 ChromeIE9I 上,Firefox 則不在支援之列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 引用兩個軟體包
require 'watir-webdriver'
require 'watir-webdriver-performance'

# 創建 Chrome 瀏覽器實例
b = Watir::Browser.new :chrome

# 做十次圈廻
10.times do
  # 瀏覽器重定向到指定 URL
  b.goto 'http://watir.com'
  # 從性能統計資訊中取出頁面的響應時間并轉換成秒單位
  load_secs = b.performance.summary[:response_time]/1000
  # 輸出本次圈迴取樣的頁面響應時間值
  puts "裝載時間: #{load_secs} 秒."
end

運行此段代碼,會得到類似下面的提示資訊内容:

裝載時間: 1.701 秒.
裝載時間: 0.694 秒.
裝載時間: 3.074 秒.
裝載時間: 1.761 秒.
裝載時間: 2.096 秒.
裝載時間: 2.823 秒.
裝載時間: 2.322 秒.
裝載時間: 1.808 秒.
裝載時間: 1.061 秒.
裝載時間: 0.766 秒.

可用的測量符號列表:

  • :summary
  • :navigation
  • :memory
  • :timing

截圖

Watir-WebDriver 已經内建了非常好用的截圖功能,可以通過類似下面的代碼調用:

1
browser.driver.save_screenshot 'screenshot.png'

更棒的一點是,截圖會將整個頁面中的内容完整都截取成圖片,而不是僅僅截取網頁的可見部分。如果同時在使用 Cucumber ,將圖片嵌入到 HTML 報告中也非常容易,將下面的代碼添加到 env.rb 档案中即可:

1
2
3
4
After do |scenario|
  browser.driver.save_screenshot 'screenshot.png'
  embed 'screenshot.png', 'image/png'
end

傳送特殊鍵

如需向特定元素或瀏覽器頁面傳送特殊鍵,可以使用 .send_keys 方法,用特定符號代指特定的特殊鍵,如:

1
b.send_keys :enter

也可以這麽用:

1
b.element.send_keys [:control, 'a'], :backspace

也可以結合發送特殊鍵的同時觸發元素的點擊事件:

1
b.element.click(:shift, :control)

完整的特殊鍵列表可參見 keys.rb

  • :null
  • :cancel
  • :help
  • :backspace
  • :tab
  • :clear
  • :return
  • :enter
  • :shift
  • :left_shift
  • :control
  • :left_control
  • :alt
  • :left_alt
  • :pause
  • :escape
  • :space
  • :page_up
  • :page_down
  • :end
  • :home
  • :left
  • :arrow_left
  • :up
  • :arrow_up
  • :right
  • :arrow_right
  • :down
  • :arrow_down
  • :insert
  • :delete
  • :semicolon
  • :equals
  • :numpad0
  • :numpad1
  • :numpad2
  • :numpad3
  • :numpad4
  • :numpad5
  • :numpad6
  • :numpad7
  • :numpad8
  • :numpad9
  • :multiply
  • :add
  • :separator
  • :subtract
  • :decimal
  • :divide
  • :f1
  • :f2
  • :f3
  • :f4
  • :f5
  • :f6
  • :f7
  • :f8
  • :f9
  • :f10
  • :f11
  • :f12
  • :meta
  • :command

頁面物件

頁面物件模式是一種將頁面及其元素構寫成可再利用類的方式,Watir-Webdriver Wiki 對此概念有比較完整的描述。

有一些 Gem 套件可以幫助我們來實現頁面物件:

大概看了一下一些資料的介紹,估計是需要再獨立消化的内容了。以後有機會再來消化這裡提到的資料中的概念與用法。

至此,Watir-Webdriver 的常規用法就基本整理完了,希望對想學習這套測試框架的同學們有所幫助,謝謝關注。

關於 Ruby、Cucumber、Debug 運行環境的幾個小細節

之前在看 Watir-Webdriver 官方教程中提到了 Cucumber 。所以就大概瀏覽了一些關於這個的資料。Cucumber 是對 BDD(Behaviour-Driven Development,也就是行爲驅動開發,由 Dan North 創立,鼓勵軟體項目中的各種角色相互協作:開發人員、QA、非技術角色或業務分析師)的一種實作。

由於 Ruby 語言使於創建和使用 DSL 特性,所以兩個非常好用的 BDD 功能也都是基於 Ruby 實現的。在 Cucumber 之前還有一個叫 Rspec 的工具也是 BDD 的實作,算是 Cucumber 的前輩(同時,Cucumber 工具包也依賴 Rspec 工具包)。Cucumber 可以用來測試 Java.NETFlex 等語言。

Cucumber 档案語言使用:Gherkin,其可附於各種自然語言,關於字爲:GivenAnd等。可以應用於:“給系統管理用作 Web 應用的集成測試”、“將分佈式系統集成并測試消息機制”、“編寫 PDF 的測試”等各種場景。

今天這篇文章主要是把從網絡上收集到的一些 RubyGemCucumberRuby-Debug 環境安裝時要注意的情况羅列出來,希望更多在同學可以節省安裝環境時所需要時間:

首先是關於 Ruby 和 Gem 基本環境,在 Mac OS X 平臺上使用 Ruby 環境是非常簡單的,這一點之前的文章裏也提到了,這裡主要說的是 Windows 平臺上的問題,由於在 Windows 平臺上要依賴蠻多的額外組件,所以個人不是太推薦從 Ruby 開始裝基礎環境,然後再 Gem 等環境一路搭建起來,至少不推薦非開發人員這樣裝,一來太花時間,二來也有時候也是問題多多。這裡推薦大家直接安裝 Rails Installer 集合環境包,安裝包裏包含了我們要使用的大部分組件或者基礎性的組件,比如:DevKit ,在 Windows 平臺上没有這個組件,很多 Gem 都没有辦法正常安裝。

安裝完成并基本配置後(官方網站上有配置的介紹視訊資料),首先是對基本環境進行升級,Rails Installer 的集合環境版本自然不會快過開源社區的項目升級,所以安裝好後首先是把環境更新到最後,然而從 RPC.China 升級 Gem 環境是一件非常痛苦的事情,默認的軟體源連接非常緩慢。好在 淘寶 RubyGem 網站在網絡上搭建了一個 Gem 源的鏡像伺服器,連接速度非常快且同步頻繁,質量很讚。這裡將系統的連接源改成淘寶源:

1
2
3
4
5
6
7
8
9
10
11
12
# 查看當前的源伺服器列表
$ gem source list
# 删除默認的源,我這裡的默認源是:http://rubygems.org
$ gem source --remove http://rubygems.org
# 清除本地緩存
$ gem source --clear-all
# 添加淘寶的源
$ gem source --add http://ruby.taobao.org/
# 再次查看伺服器列表,確認源已添加到列表中
$ gem source list
# 更新本地的源快取
$ gem source --update

接着,更新 Gem 系統和所有已安裝的 Gem 軟體包:

1
2
3
4
# 更新 Gem 系統本身
$ gem update --system
# 更新所有已安裝的 Gem 軟體包
$ gem update

如此, Gem 系統及所有已安裝軟體包都已經更新到最新,這樣就可以開始安裝 Cucumber 軟體包了,大部分依賴關係基礎組件中已包含,現在按順序安裝其他軟體包即可,這過程中我們順便把 Watir 系統軟體包也裝上:

1
2
3
4
5
6
7
8
9
10
11
12
# 安裝依賴Gem: rspec
$ gem install rspec --no-ri --no-rdoc
# 解决 Win32 下 Console 字符讀入問題
$ gem install win32console --no-ri --no-rdoc
# 安裝 Watir 測試框架
$ gem install watir
# 安裝 Watir-WebDriver 測試框架
$ gem install watir-webdriver --no-ri --no-rdoc
# 安裝 依賴Gem: gherkin
$ gem install gherkin
# 最後,安裝 cucumber
$ gem install cucumber --no-ri --no-rdoc

Cucumber 就安裝好了。另外再把 ruby-debug 套件安裝上,雖然我不太用 Aptana ,不過喜歡用這個 IDE 工具的同事還是蠻多的,可能很多人都發現剛裝好的 Aptana 没法使用調試器,這裡把調試器也一并裝上,方便將來使用:

1
2
$ gem install ruby-debug-ide19
$ gem install ruby-debug-base19

之後再運行 Aptana 或者安裝了 Aptana 外掛程式的 Eclipse 就可以正常使用 ruby-debug 了。至此一個可用的 Cucumber + Watir-Webdriver 環境就搭建完成了。

本文參考了以下幾篇文章:

Watir-Webdriver 一些常規測試的實現方法(上)

基本型瀏覽器身份認證

這個應該不算是 Watir-Webdriver 的功能,有一些網頁利用瀏覽器的進行身份認證。比如路由器的登錄頁面就會請求瀏覽器彈出一個身份認證界面用於用戶輸入帳戶與密碼。

Example Basic Browser Authentication Dialog

最優雅的方法應該就是在請求 URL 中加入帳戶密碼,這樣例可完全跳過對話框驗證過程:

1
2
3
require 'watir-webdriver'

b = Watir::Browser.start 'http://admin:password@yourwebsite.com'

安全證書

Firefox

Firefox 驅動在默認情況會阻止不可靠證書。即使我們擁有合法證書,也可能因為如主機名稱不匹配等問題而造成瀏覽器的證書信任危機,可以通過設定瀏覽器實例配置項 assume_untrusted_certificate_issuer 來忽略證書信任的問題:

1
2
3
profile = Selenium::WebDriver::Firefox::Profile.new
profile.assume_untrusted_certificate_issuer = false
b = Watir::Browser.new :firefox, :profile => profile

詳細的解釋可參見:Untrusted SSL Certificates Implementation Details

Chrome

Chrome 瀏覽器中想要忽略證書錯誤是非常容易的,只要在創建實例的時候使用特定的開關選項 ignore-certificate-errors 即可:

1
Watir::Browser.new :chrome, :switches => ['--ignore-certificate-errors']

瀏覽器下載行為

對於測試程式來說,最好也是最方便的檔案下載體驗是完全取消瀏覽器的下載確認對話框。可以通過編程的方式驅動瀏覽器實例自動下載檔案到測試程式所能訪問的路徑下。

Firefox

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 生成檔案下載目錄路徑,即當前目錄下的 downloads 子目錄
download_directory = "#{Dir.pwd}/downloads"
# 如果當前操作系統平臺是 windows , 則將路徑分隔符轉為字元 \
download_directory.gsub!("/", "\\") if Selenium::WebDriver::Platform.windows?

# 這一段以前看過了,創建 Profile ,設定瀏覽器的默認下載目錄
profile = Selenium::WebDriver::Firefox::Profile.new
profile['browser.download.folderList'] = 2 # custom location
profile['browser.download.dir'] = download_directory

# 通過 browser.helperApps.neverAsk.saveToDisk 設定不詢問,直接下載的檔案 MIME 類型
profile['browser.helperApps.neverAsk.saveToDisk'] = "text/csv,application/pdf"

# 最後利用生成好的 Profile 創建瀏覽器實例
b = Watir::Browser.new :firefox, :profile => profile

隨帶一提前面説過的,所有的可用配置項都可以通過 URL 地址: about:config 查看。如果想知道關於利用 MIMEWatir-Webdriver 結合工作的詳細資料,可參見:Determining file MIME types to autosave using Firefox & Watir-WebDriver

Chrome

1
2
3
4
5
6
7
8
download_directory = "#{Dir.pwd}/downloads"
download_directory.gsub!("/", "\\") if Selenium::WebDriver::Platform.windows?

profile = Selenium::WebDriver::Chrome::Profile.new
profile['download.prompt_for_download'] = false
profile['download.default_directory'] = download_directory

b = Watir::Browser.new :chrome, :profile => profile

Chrome 中的設定方式與 Firefox 大致相同,不同的只是 Key 名稱,download.prompt_for_download 值為 false 可取消下載確認詢問,download.default_directory 值設定下載的默認目錄。

詳細的屬性列表可見:Chrome Preferences

操作彈出窗口

當開啟了一個新窗口後,可以使用 use 方法,傳入一個語句塊來做想做的事情:

1
2
3
browser.window(:title => "annoying popup").use do
    browser.button(:id => "close").click
end

更多例程可參考:Window Switching Spec

瀏覽器代理

例程:為 Firefox 設定 http 或 https 代理

1
2
3
4
5
6
profile = Selenium::WebDriver::Firefox::Profile.new

# 新建 Selenium::WebDriver::Proxy 實例,指定 `http` 和 `ssl` 參數指明代理伺服器 URL。將其添加到配置檔案中
profile.proxy = Selenium::WebDriver::Proxy.new :http => 'my.proxy.com:8080', :ssl => 'my.proxy.com:8080'

browser = Watir::Browser.new :chrome, :profile => profile

例程:為 Chrome 設定 http 或 https 代理

1
2
3
# 使用 --proxy-server 指定代理伺服器 URL
switches = '--proxy-server=my.proxy.com:8080'
browser = Watir::Browser.new :chrome, :switches => switches

Cookies

Watir-WebDriver v0.5.2 以上支援 Cookies API,非常易用:

1
2
3
4
5
6
7
require 'watir-webdriver'

browser = Watir::Browser.new
browser.cookies.clear
browser.cookies.add 'foo', 'bar', :path => "/", :expires => 10.days.from_now, :secure => true
browser.cookies.delete 'foo'
browser.cookies.to_hash

所有的方法都包含在了瀏覽器實例成員 cookies 中,如常見的 clear 清除,add 添加,delete 刪除等操作。

檢測瀏覽器品牌

可以通過瀏覽器實例輕鬆地查看瀏覽器品牌:

1
2
3
4
require 'watir-webdriver'

b = Watir::Browser.new :chrome
browser.driver.browser #返回值是 :chrome

JavaScript 對話框

JavaScript 對話框 普遍存在於網頁應用程式中(這倒也未必,事實上現代網頁中用得並不多)。Watir-Webdriver 包含了內建程式庫來處理對話框,並可與詢問對話框進行內容交互,使用這些功能需要引用相應的擴充模組:watir-webdriver/extensions/alerts:

1
require "watir-webdriver/extensions/alerts"

alert 函式

1
2
3
browser.alert do
    browser.button(:value => 'Alert').click
end #=> 'the alert message'

confirm 函式

1
2
3
browser.confirm(true) do
    browser.button(:value => 'Confirm').click
end #=> 'the confirm message'

prompt 函式

1
2
3
browser.prompt('hello') do
    browser.button(:value => 'Prompt').click
end #=> { :message => 'foo', :default_value => 'bar' }

因為這些對話框都屬於模態對話框所以就不再需要像元素那樣搜索了,alert 方法可激發 alert 對話框 的點擊行為,confirmprompt分別可處理 是非對話框(傳 布林 類別參數值決定點擊確定或取消按鈕) 和 詢問對話框(依 字串 參數值作為窗口標題,決定要處理的對話框)。

可選方案

事實上這並不是一個 Watir-Webdriver 方案,如果在使用上面提到的方案時出現異常(相當多的時候會有這種情況),可以使用下面的方法來修改 JavaScript 內建方法的實現:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 重寫 alert 函式實現,變成空方法且不返回任何值
browser.execute_script("window.alert = function() {}")

# 重寫 prompt 函式實現,設定返回值字串,用以模擬用户的字串輸入
browser.execute_script("window.prompt = function() {return 'my name'}")

# 重寫 prompt 函式實現,返回 null 值,模擬用户點擊了取消按鈕
browser.execute_script("window.prompt = function() {return null}")

# 重寫 confirm 函式實現,返回 true 值,模擬用户點擊了 OK 按鈕
browser.execute_script("window.confirm = function() {return true}")

# 重寫 confirm 函式實現,返回 false 值,模擬用户點擊了 Cancel 按鈕
browser.execute_script("window.confirm = function() {return false}")

利用 execute_script 方法在瀏覽器實例上執行 JavaScript 代碼覆蓋瀏覽器宿主原本的內建方法實現,使所有內建對話框函式失效。

Watir-Webdriver 元素控制與延時等待

上次在《Watir 自動化測試框架基礎知識》篇中,我們大概學習了如何利用 Watir-Webdriver 來驅動 ChromeFirefoxInternet Explorer 這三個瀏覽器,並實踐了最簡單的示例:創建一個瀏覽器實例、為實例設定配置檔案、設定瀏覽器利用的代理伺服器信息、關閉瀏覽器實例。現在來學習一些測試實現中經常要用到的一些基礎性操作。

操作網頁元素

文本框

1
2
3
4
5
6
7
require 'watir-webdriver'

b = Watir::Browser.start 'bit.ly/watir-webdriver-demo'
t = b.text_field :id => 'entry_0'
t.exists?
t.set 'your name'
t.value

在前面的示例中,我們都是使用 Watir::Browser.new 來指定創建特定瀏覽器實例,再進一步處理。但這裡出現的內容與方法適用於所有的支援的瀏覽器,所以這裡直接 Watir::Browser.start 創建默認的瀏覽器實例,並直接定向到指定的 URL 。當然如果你想指定 URL 同時還是要指定瀏覽器也非常容易,調用 start 方法時把指名參數也加進去就好了:

1
b = Watir::Browser.start('google.com' , Browser = :firefox)

我們在操作一個頁面上的元素前,需要先獲取到這個元素物件的引用,基本型元素的選取都可通過瀏覽器實例物件(即上文中創建的物件 b)所包含的物件選取方法來獲取引用。這裡我們需要選取的是 文本框,所以我們要利用的是 text_field 方法。

通過向 text_field 方法傳遞參數 :id'entry_0',表明想要選取一個 id 值為 entry_0HTML DOM 元素。方法在調用完成後會返回元素的引用,所以這裡創建了一個變數 t 來存放元素引用。值得注意的是,使用常規元素獲取方法總會得到的 TextField 物件引用(亦即是上文源碼中的 t),不會得到 nil 物件。

但此物件是否確實指向頁面中一個存在的元素卻尚未可知。所以我們還需要對其所指向的元素存在性進行檢測,利用物件的 exists? 方法可檢測存在性。

set 方法可以在文本輸入框輸入指定的字串,代碼最後一行是 t.value ,在 irb 中鍵入這段指令後,可以在交互環境中看到文本輸入框中修改過的結果。

列表框

1
2
3
4
5
6
require 'watir-webdriver'

b = Watir::Browser.start 'bit.ly/watir-webdriver-demo'
s = b.select_list :id => 'entry_1'
s.select 'Ruby'
s.selected_options

select_list 方法用於選取列表框元素,select 用於從列表框中選取指定值的項目,selected_options 可返回列表框中所有選中的項目的陣列。

單選按鈕組

1
2
3
4
5
6
7
require 'watir-webdriver'

b = Watir::Browser.start 'bit.ly/watir-webdriver-demo'
r = b.label(:text => 'What is ruby?').parent.radio :value => 'A gem'
r.exists?
r.set
r.set?

r = b.label(:text => 'What is ruby?').parent.radio :value => 'A gem' 稍顯複雜。大概申明一下 ruby 的文法規則:在主義明確的情況下方法調用時可以不用括號將參數括起來。但在這裡的處理邏輯是在獲取指定元素後再找到其父元素節點,所以在 b.label(:text => 'What is ruby?').parent 的調用中使用括號來包含 label 方法的調用參數。

b.label(:text => 'What is ruby?').parent.radio :value => 'A gem' 中還可以看出別一個特點,在指定 radio 元素的父級元素節點物件上也可以調用元素提取功能(text_fieldselect_listlabel 這類方法),那麼也就是說在任何確定的元素物件上都可以進行元素節點範圍內的元素搜尋與提取(如上文中,就是以 text 值為:What is ruby? 的單選按鈕的父級節點為根節點,在範圍內再搜尋 value 值為:A gem 的單選按鈕元素引用)。

Watir-Webdriver 也遵循了 ruby 一貫的簡潔風格,set方法用於選中這個單選按鈕,set?方法即可檢測出單選按鈕是否被選中,好記好用。

可複選按鈕

1
2
3
4
5
6
7
require 'watir-webdriver'

b = Watir::Browser.start 'bit.ly/watir-webdriver-demo'
c = b.label(:text => 'What versions of ruby?').parent.checkbox :value => '1.9.2'
c.exists?
c.set
c.set?

checkbox 用來提取可複選按鈕元素。注意哦,單選按鈕組間按鈕狀態是互異的,所以不存在取消選中狀態這種情况。而 checkbox 則是有取消選中狀態這種操作的,所以同樣是 set方法,checkbox 元素物件的 set方法是可以傳參的。默認不帶參數的調用會選中可復選按鈕,傳入 false 值參數後即可取消按鈕的選中狀態。

按鈕

1
2
3
4
5
6
require 'watir-webdriver'

b = Watir::Browser.start 'bit.ly/watir-webdriver-demo'
btn = b.button :value, 'Submit'
btn.exists?
btn.click

button 方法用於提取按鈕元素, click 方法可以觸發按鈕的點擊行爲。

鏈接

1
2
3
4
5
6
require 'watir-webdriver'

b = Watir::Browser.start 'bit.ly/watir-webdriver-demo'
l = b.link :text => 'Google Docs'
l.exists?
l.click

link 方法用於提取鏈接元素

行級區塊 & 內聯區塊

1
2
3
4
5
6
7
8
9
require 'watir-webdriver'

b = Watir::Browser.start 'bit.ly/watir-webdriver-demo'
d = b.div :class => 'ss-form-desc ss-no-ignore-whitespace'
d.exists?
d.text
s = b.span :class => 'ss-powered-by'
s.exists?
s.text

div 方法用於提取行級區塊元素 <div>span 方法用於提取內聯區塊元素 <span>,這裡又看到一個參數 :class 可以通過元素的 class 屬性值篩選匹配。而 text 方法可以從區塊中取出文本。

框架

Watir-WebDriver 中操作框架與操作其他元素一樣,都是非常容易的:

1
b.frame(:id => "content_ifr").send_keys "hello world"

以上就是常規的元素提取方法了,另外還有一小篇關於所見即所得編輯器的處理方法:

所見即所得編輯器

通過 Watir-Webdriver 有兩種方式操作 所見即所得編輯器

  • 取得 iFrame 元素後使用 send_keys 方法來輸入文本(缺點是:瀏覽器必須處於前臺,也就是激活狀態)
  • 於瀏覽器物件上執行 JavaScript ,向編輯器設定文本內容(這種方法較為可靠)

CKEditor

1
2
3
4
5
6
7
8
9
10
11
require 'watir-webdriver'

b = Watir::Browser.new :firefox
b.goto 'http://ckeditor.com/demo'

# 通過 CKEditor 內建方法向編輯器添加文本內容
b.execute_script("CKEDITOR.instances['editor1'].setData('hello world');")

# 通過向內嵌框架 `send_keys` 改善文本內容
b.frame(:title => 'Rich text editor, editor1, press ALT 0 for help.').send_keys 'hello world
again'

TinyMCE

1
2
3
4
5
6
7
8
9
10
require 'watir-webdriver'

b = Watir::Browser.new
b.goto 'http://tinymce.moxiecode.com/tryit/full.php'

# 通過 TinyMCE 內建方法向編輯器添加文本內容
b.execute_script("tinyMCE.get('content').execCommand('mceSetContent',false, 'hello world' );")

# 通過向內嵌框架 `send_keys` 改善文本內容
b.frame(:id => "content_ifr").send_keys 'hello world again'

以上以兩種常見的所見即所得編輯器為例,分別演示了兩種不同的向編輯器發送文本內容的方式。frame 方法可以用於提取框架元素,execute_script方法則可直接在瀏覽器實例空間中運行腳本代碼,這個功能有點類似於 JavaScript 中的 eval 函式的作用。

延時等待

等待操作(Waiting )是在進行動態界面網頁(比如使用了大量 Ajax 應用的網站)測試時經常遇到的問題。

四種 Wating 方法

有四種內建方法更適合用於 Wating 工作,這樣我們就可以拋棄讓人有點鬱悶的 Sleep Wating 了。

  • Watir::Wait.until { ... } :等待,直到語句塊中返回值為 true
  • object.when_present.set :設定物件出現後執行的方法
  • object.wait_until_present:等待,直到物件出現
  • object.wait_while_present:等等,直到物件消失

這些方法的默認超時時間為 30s,當然也可以在調用方法時傳遞 timeout 參數(單位:秒)來增加或減少超時時間設定。

1
2
3
4
5
6
7
8
require 'watir-webdriver'

b = Watir::Browser.start 'bit.ly/watir-webdriver-demo'
b.select_list(:id => 'entry_1').wait_until_present
b.text_field(:id => 'entry_0').when_present.set 'your name'
b.button(:value => 'Submit').click
b.button(:value => 'Submit').wait_while_present
Watir::Wait.until { b.text.include? 'Thank you' }

注意哦,b.text.include? 中的 include? 方法是字串類别的。

潜在 Waiting 行为設定

作为一种可配置选项,可以使用 WebDriver 通过底层驱动属性对潜在 Waiting 参数进行制定。通过修改浏览器实例的 driver.manage.timeouts.implicit_wait 属性值(单位:秒)进行控制。

1
2
3
4
require 'watir-webdriver'

b = Watir::Browser.new
b.driver.manage.timeouts.implicit_wait = 3 #3 seconds

此属性指定在超时前,测试程式尝试搜寻元素(例如:.select_list.button)所能使用的的最大时长(也可以认为是元素搜寻的超时时间设定值)。要注意的是使用此设定值可能会使得测试程式变慢,也可能会使一些测试错误更难于理解。

關於從 OSX 利用 Rsync+SSH 向 FreeBSD 主機部署資料的說明

原本想着在網路上建立資料同步主機會很麻煩,而且還要額外再考慮安全問題。不過這次嘗試去部署的時候才發現和想像的不同。Octopress 部署資料的時候并不依賴 Rsync 伺服器,而是依賴用户端 rsync 程式的支援。 Mac OS X Lion 已經内置了 rsync 程式,這個就不需要再操心了。Octopress 在部署前需要與伺服器使用 SSH 連接,然後在此基本上進行目錄資料同步,而 Octopress 不支援用户名/密碼模式連線。

所以,需要利用 SSH 證書登錄方式。使用 sysinstall 交互界面建立一個新用户并賦予一個最低的用户權限。之後需要利用這個用户作爲連線基礎。在這之前要先在本地計算機上生成一組密鑰:

1
$ ssh-keygen -t rsa -b 2048

接着會進入交互指令模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
➜  octopress git:(master) ✗ ssh-keygen -t rsa -b 2048
Generating public/private rsa key pair.
Enter file in which to save the key (~/.ssh/id_rsa): [直接按下 Enter 鍵即可]
Enter passphrase (empty for no passphrase): [直接按下 Enter 鍵即可]
Enter same passphrase again:
Your identification has been saved in ~/.ssh/id_rsa.
Your public key has been saved in ~/.ssh/id_rsa.pub.
The key fingerprint is:
c1:54:h7:3d:hg:99:3r:xc:g2:wa:56:2f:k9:3h:l0:6y test@pointpoint.local
The key's randomart image is:
+--[ RSA 2048]----+
|                 |
|    o.          .|
|     .           |
|                 |
|      .    oo    |
|                 |
|   oo        .   |
|                 |
|   .       oo    |
+-----------------+

提示輸入密鑰的兩處地方,直接按下 Enter 就可以了。如此便會生成

  • ~/.ssh/id_rsa 此是私鑰
  • ~/.ssh/id_rsa.pub 此是公鑰

老實利用 scp 指令,複製公鑰到伺服器上:

1
scp ~/.ssh/id_rsa.pub rsync_user@server.com:~/

在輸入用户的密碼後,公鑰便會複製到伺服器用户的家目錄下。參考一下伺服端的 SSHD 配置档案:

1
more /etc/ssh/sshd_config

可以在配置档案中,可以看到伺服程式的默認設定值:

1
#AuthorizedKeysFile     .ssh/authorized_keys

也就是說 SSHD 伺服程式會將用户目錄下 ~/.ssh/authorized_keys 档案作爲認證當前用户登錄的認證公鑰档案。把之前複製到的公鑰档案灌入到這個档案,并重設档案權限即可:

1
2
3
cat ~/id_rsa.pub >> ~/.ssh/authorized_keys
chmod 0600 ~/.ssh/authorized_keys
rm ~/id_rsa.pub

如此,就可以從生成公、密鑰的主機上直接登錄到伺服器了。這裡再對登錄用户再稍作一些權限限制,首先創建一個腳本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/bin/sh

case "$SSH_ORIGINAL_COMMAND" in
  *&*)
      echo "Rejected"
      ;;
  *(*)
      echo "Rejected"
      ;;
  *{*)
      echo "Rejected"
      ;;
  *;*)
      echo "Rejected"
      ;;
  *<*)
      echo "Rejected"
      ;;
  *`*)
      echo "Rejected"
      ;;
  rsync --server*)
      $SSH_ORIGINAL_COMMAND
      ;;
  *)
      echo "Rejected"
      ;;
esac

档案存儲到用户目錄下,eg: ~/validate-rsync 。接着編輯 ~/.ssh/authorized_keys 档案,档案以

1
ssh-rsa GFDFRBVD

形式開頭,在 ssh-rsa 後添加剛才生成腳本的路徑,修改成類似:

1
ssh-rsa command="~/validate-rsync" GFDFRBVD

的形式。如此設定後此用户在利用密鑰登錄後,用户指令在一定程度上有所限制。

最後配置 Octopress 目錄中的配置档案 Rakefile

1
2
3
4
5
6
# 用户登陸 URL
ssh_user       = "user@domain.com"
# 同步資料的目錄路徑
document_root  = "~/website.com/"
rsync_delete   = true
deploy_default = "rsync"

完成這些設定後,使用如下指令即可向伺服器推送資料了:

1
2
3
4
# 生成所有的網頁
rake generate
# 將生成的網頁部署到伺服器
rake deploy

Watir 自動化測試框架基礎知識

網頁自動化測試

其實關於網頁自動化測試不是我的本職工作,不過上次見到網路上的自動化測試演示時,非常的喜歡。所以最近考慮關注一小部分關於網頁自動化測試的資料。

基本上網路上看到最多的資料就是 Watir 這個自動化測試框架了。Watir 是基於 Ruby 語言環境構建的,在 Ruby 高度靈活上的語言環境之上,為自動化測試框架帶來了非常不錯的體驗,國內像是比較有名的網站:淘寶之前自己出來說使用的自主開發的測試框架 AutoMan 也是使用 Watir 作為基礎的。

由於 Watir 支援的瀏覽器並不多,Watir 支援的是 Windows 平臺上的 Internet Exploer,另外有一個 SafariWatir 支援的是 Mac OS X 平臺上的 Safari 瀏覽器。這使得網頁測試被限制在特定的平臺與瀏覽器上。這才有了現在在看的 Watir-Webdriver 測試框架。Watir-Webdriver 在後端使用網上非常流行的測試框架 Webdriver 作為支撐。Watir-Webdriver 是對其進行的封裝後的產物,這樣就保持了 Watir 的利用習慣。框架可以利用的瀏覽器包括:FireFoxChromeInternet Explorer。但暫不支援 Safari,不過支援度已經非常高了。

這裡順帶一提:Watir 是 :

Web Application Testing in Ruby

的縮寫形式,讀音不明(或者讀作:Water?)。

可以簡單利用 gem 來安裝 Webdriver 測試套件:

1
$ gem install watir-webdriver

要記住的是,Watir-Webdriver需要 1.9.2 版本以上的 Ruby 支援,低版本的 Ruby 會出現工作異常。安裝完成後,就可以通過irb指令進入 Ruby 交互環境,交互環境適合我們試驗一些臨時性代碼和功能,這些代碼我們並不想保存下來,只是臨時試驗一下。irb交互環境為我們提供了這樣的便利環境。

現在可以在交互環境下試驗下面這段代碼,來體驗一下 Watir-Webdriver 的神奇之處:

1
2
3
4
5
6
7
8
9
require 'watir-webdriver'

b = Watir::Browser.new
b.goto 'bit.ly/watir-webdriver-demo'
b.text_field(:id => 'entry_0').set 'your name'
b.select_list(:id => 'entry_1').select 'Ruby'
b.select_list(:id => 'entry_1').selected? 'Ruby'
b.div(:class => 'ss-form-entry').button.click
b.text.include? 'Thank you'

Watir-Webdriver 官方推薦 Cucumber + Watir-Webdriver 的組合,Cucumber 是一個能夠理解用自然語言描述的測試用例的支援行為驅動開發(BDD)的自動化測試工具。這個留到後面再學習。

驅動 Chrome 瀏覽器

ChromeDriver

Watir-Webdriver 通過專用的 ChromeDriver 進制驅動包對 Chrome 瀏覽器進行支援,ChromeDriver 是一個開源項目,網路地址是Chromium、(Watir-Webdriver官方如是說道,不過在實際使用中我們還依賴另一個開源項目:)Selenium ChromeDriver(on Google Wiki)。這裡要先在系統中為安裝好 Chrome 驅動包,否則在調用相關功能代碼時會出現異常:

irb(main):003:0> b = Watir::Browser.new :chrome , :switches => %w[–disable-popupblocking] Selenium::WebDriver::Error::WebDriverError: Unable to find the chromedriver executable. Please download the server from http://code.google.com/p/chromedriver/downloads/list and place it somewhere on your PATH. More info at http://code.google.com/p/selenium/wiki/ChromeDriver.

通過 Chromium 項目列表可以下載到瀏覽器功能擴充包 codesite.crx,直接將檔案拖到 Chrome 瀏覽器界面,確認瀏覽器安裝詢問,即可完成安裝,接著在 Selenium ChromeDriver 項目列表中可以下載到 ChromeDriver Server 程式壓縮包,名稱隨版本升級而變化,我下載的時候最新版本是:chromedriver_win_19.0.1068.0,將壓縮包中的檔案 chromedriver.exe 解壓,放入文件系統中。在試驗環境,我將 chromedriver.exe 存儲到 C:\watirs\ 目錄下,然後向操作系統的環境變數 PATH 中添加了伺服驅動程式檔案的存儲路徑:C:\watirs\,這樣就完成了驅動包的安裝與設定功能。

通過傳遞特定參數,可創建 Chrome 瀏覽器實例:

1
2
# :chrome 參數指明創建的目標物件是 chrome 瀏覽器實例
b = Watir::Browser.new :chrome

Chrome Profiles

通過 Profiles ,可對創建的 Chrome 瀏覽器實例進一步配置:

1
2
3
4
5
6
7
8
# 新建 Profile 實例
profile = Selenium::WebDriver::Chrome::Profile.new
# 取消下載確認過程
profile['download.prompt_for_download'] = false
# 設定默認的下載路徑
profile['download.default_directory'] = "/path/to/dir"
# 創建瀏覽器實例的時候將 Profile 物件轉入構造函式,初始化瀏覽器
b = Watir::Browser.new :chrome, :profile => profile

完整的可選配置項可參見源碼檔案:pref_names.cc

Chrome Switches

除了可選配置外,還可以使用參數設定一些開關值選項:

1
b = Watir::Browser.new :chrome, :switches => %w[--ignore-certificate-errors --disable-popupblocking --disable-translate]

完整的開關值列表可參見源碼檔案:chrome_switches.cc

Chrome 代理伺服器設定

這個其實也是 switches 功能,不過我們可能經常用到,所以這裏單獨列出來,一行示例源碼即可:

1
2
# 創建瀏覽器實例時,設定代碼伺服器為:myproxy.com 端口號為:8080
b = Watir::Browser.new :chrome, :switches => %w[--proxy-server=myproxy.com:8080]

驅動 Firefox 瀏覽器

即時可用®

對於 Firefox 瀏覽器的支援是基於一個 JavaScript驅動完成的,所以在所有平臺上的 FireFox 上都直接可用:

1
b = Watir::Browser.new :firefox

Firefox Profiles

默認的情況下,Firefox 驅動會為每個測試進程新增一個全新的配置檔案,這也是被推薦的創建行為。當然,如果堅持要使用一個現有的配置檔案也是可以的:

1
b = Watir::Browser.new :firefox, :profile => 'default'

和在 Chrome 瀏覽器中一樣,我們也可以修改配置檔案的特定選項內容:

1
2
3
4
5
6
7
profile = Selenium::WebDriver::Firefox::Profile.new
# 設定默認的下載路徑
profile['browser.download.dir'] = "/tmp/webdriver-downloads"
profile['browser.download.folderList'] = 2
# 取消瀏覽器的下載前需確認的行為
profile['browser.helperApps.neverAsk.saveToDisk'] = "application/pdf"
b = Watir::Browser.new :firefox, :profile => profile

完整的選項列表在哪裡呢?比較好找,找開 Firefox 瀏覽器,在地址欄中輸入 about:config 指令,即可打開瀏覽器的特性列表,列表中的所有 Key 值都可以設定到 Profile 中。

關於Microsoft Window 版本 FireFox 的本地化特性事件

在 Microsoft Window 平臺上發行的 FireFox 默認情況支援本地化特性事件,並且在操作系統與 WebDriver 間提供一個低級交互層。不管怎麼樣,可能會在特定條件下出現錯誤。如果需要禁用這個能力,可以為 Firefox 實例添加一個指定選項的 Profile

1
2
3
4
profile = Selenium::WebDriver::Firefox::Profile.new
# 如果 Key 鍵名不是包含 . 符號的字元串,還是下面這種方式寫起來比較方便
profile.native_events = false
Watir::Browser.new :firefox, :profile => profile

Firefox 代理伺服器設定

設定伺服器信息,同樣也是對 Profile 的設定,看一下示例代碼便可:

1
2
3
profile = Selenium::WebDriver::Firefox::Profile.new
profile.proxy = Selenium::WebDriver::Proxy.new :http => 'myproxy.com:8080:, :ssl => 'myproxy.com:8080'
b = Watir::Browser.new :firefox, :profile => profile

Firebug 與 Watir-WebDriver 結合使用

對於 Firebug ,大家都比較熟悉了。她是 Firefox 下著名的網頁調試工具,可以用來調試網頁中的 JavaScript 代碼,CSS 樣式,HTML DOM 結構等各種功能。在創建 Profile 的同時指定擴充功能程式檔案包位置,即可使實例創建時開啟指定的擴充程式功能。

1
2
3
profile = Selenium::WebDriver::Firefox::Profile.new
profile.add_extension "../path/to/firebug.xpi"
b = Watir::Browser.new :firefox, :profile => profile

Microsoft Window Internet Explorer

Window 上的 Internet Explorer

這就是句廢話,Internet Explorer(以下簡稱為:IE) 自然是 Window Only 的,也別指望 Watir-Webdriver 去支援 Mac OS X 上那個可憐的已經被遺忘的 IE v5.5。如果是在 Window 7 以上的操作系統中,IE 包含保護模式,如果想使 Watir-Webdriver 工作正常,則需為所有區域開放保護模式下運行的功能。然後使用參數 :ie 即可創建一個 IE 瀏覽器實例:

1
b = Watir::Browser.new :ie

Internet Explorer Config

無法為 IE 實例指定不同的配置檔案,IE 瀏覽器總是從 網際網路選項(Internet Options) 中的讀取配置信息,你所能做的僅僅是在運行測試前,通過設置對話框先行設定好配置值。

移動設備

對於 Watir-Webdriver 有三種方式來測試移動設備型站點:

  • 利用一臺真實的移動設備上嵌入式網頁瀏覽器執行測試
  • 在桌面型計算機上使用移動設備模擬機上的嵌入式網頁瀏覽器執行測試
  • 使用桌面型計算機上瀏覽器,通過創建與移動設備上網頁瀏覽器相同的分辨率與用户代理辨識碼(亦即是:user-agent)來執行測試

使用真實移動設備或者移動設備模擬機(iOSAndroid)都很昂貴,并且性能上不如桌面型網頁瀏覽器快速。關於設定 iOS 測試驅動環境的詳細档案可以參見:《Selenium iPhone Driver》,設定 Android 可參見:《Selenium Android Driver》。使用真實的蘋果設備需要蘋果的開發者帐户,帐户需要每年向蘋果公司支付 $99

比起前面的方法,更容易也更有效率的方法則是使用桌面型網頁瀏覽器進行測試,只要將瀏覽器的配置模擬成移動設備型瀏覽器即可。這裡需要用到 Webdriver-user-agent 套件:

1
2
3
4
5
6
7
8
9
10
require 'watir-webdriver'
require 'webdriver-user-agent'

# 代理邏輯比較好懂,利用 UserAgent 類别下的 driver 方法指定要模擬的瀏覽器與特性
driver = UserAgent.driver(:browser => :chrome, :agent => :iphone, :orientation => :landscape)
# 使用新創建的用户代理誤碼新建瀏覽器實例
browser = Watir::Browser.new driver

browser.goto 'tiffany.com'
browser.url.should == 'http://m.tiffany.com/International.aspx'

套件當前支援將 FirefoxChrome 桌面型瀏覽器,可將其模擬成:桌面瀏覽器、iphoneipadandroid_phoneandroid_tablet。當然也支援豎排格式及地理定位功能也均可用。

在 Mac OS X Lion(10.7.3) 上安裝 Octopress 環境的注意事項

預備知識

網路上關於安裝 Octopress 的文章蠻多的,其實官方的幫助档案 Octopress Documentation 就已經足够了,不過在不同的系統上安裝時總會出些小狀况。另外還有一些資料可以參考:

折騰 Octopress

雖然不是第一次在 Mac OS X 上折騰 ruby ,但這是我第一次比較完整的安裝相關的環境,這裡把一些安裝時遇到的問題列出來,也許有出現一樣問題的同學,可以拿來做個參考。這也是搭建完新的環境後的真正意義上的第一篇文章,正好練習練習 Markdown 語法。

Console 環境

終端機程式

"iTerm2 logo" 其實我個人對 OSX 自帶的終端機非常滿意,比起另外兩個有名的系統來說,OSX 自帶的終端機可以算得上奢華了。不過看到網上很多前輩在使用 OSX 時還是會推薦另一個替代品:iTerm2。大概試用了一下,蠻不錯的。只不過我原先對終端機的使用也僅停留在使用一些常見的指令,和用 VIM 編輯點守護精靈程式的設定档案罷了。所以暫時也没有特别深的體會,總之就先裝上好了,以後用多了估計也就體會出點特别之處了吧。iTerm2 隨預編譯程式包發佈的配色比較少,可以使用 iTerm2-Color-Schemes 項目中的配色來增加更多配色選擇,我對終端機的附加配色向來是不以爲然的,總覺得默認配色還是不錯的,反正各種腳本環境也會隨時改變輸出顏色來增强日誌閱讀。

Shell 環境

記得剛學 FreeBSD 的時候一直都是在 sh 下混過來的,對那個交互功能過少的環境真是有點無語。自己不是什麽學院派,所以對太簡陋的 CUI 環境着實比較頭痛。一般在 OSX 上搭 Ruby 環境的同學都會轉 zsh ,因爲有一個非常好用的腳本集合包:oh-my-zsh,包含了很多便利的功能。

安裝 oh-my-zsh oh-my-zsh on GitHub
1
$ wget --no-check-certificate https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh -O - | sh

Homebrew 包管理程式

"RVM logo" Homebrew 是利用 GitHub 作爲平臺的包管理工具,由 Ruby 構建。這個包管理工具類似於 FreeBSD 的 PORT 管理工具,或者 Debian 的 APT 管理工具。也就是在 OSX 平臺上建立一套編譯環境,與 OSX 平臺上其他包管理工具不同的是,由於 OSX 每次發佈的時候都自帶了大量的 Unix 工具包,Xcode 安裝後也會向系統添加很多額外的 Unix 工具包,這兩套工具包是相互兼容的。但我們要額外編譯一些 GNU 軟體包的時候就比較麻煩了,因爲可以利用的函式庫不一定都有,自己再添加的又可能污染現有的系統档案。

所以就有了 Homebrew,用於建立一個與以往不同的獨立編譯環境。它的優勢就是優先使用系統自帶的函式庫和一些依賴档案,没有的話再從自身的編譯環境中去安裝或尋找。使用這個包管理工具,就可以在系統中安裝一些不污染系統自身工具鏈的編譯環境。使用下面的指令進行安裝:

安裝 Homebrew Homebrew on GitHub
1
$ /usr/bin/ruby -e "$(/usr/bin/curl -fsSL https://raw.github.com/mxcl/homebrew/master/Library/Contributions/install_homebrew.rb)"

安裝完成後,可以按照需要制定一下配置,如:更換配色主題,開啟外掛程式等。具體參考官方說明。

RVM 管理環境

因爲同樣的原因,OSX 系統自帶了 Ruby 和 Gem 環境。只不過版本太低了,即使是最新的 Mac OS X Lion 10.7.3 系統自帶的是: Ruby 1.8.7,Gem 1.3.6。爲了不破壞系統自帶的 Ruby 環境,所以要利用 RVM 管理工具在本地建立另一套 Ruby 環境。下面是一些關於 RVM 的部署資料:

安裝 Octopress 的時候,因爲 Ruby 和 Xcode 環境比較新帶來的問題,參考了以下幾篇文章:

使用下面的指令安裝 RVM,并安裝新版的 Ruby 并切換到 1.9.3:

安裝 RVM,Ruby 1.9.3 RVM
1
2
3
4
5
$ bash < <(curl -s https://rvm.beginrescueend.com/install/rvm)
$ echo '[[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm" # Load RVM function' >> ~/.bash_profile
$ source ~/.bash_profile
$ rvm install 1.9.3 --with-gcc=clang
$ rvm use 1.9.3

安裝 RVM 時,可能會出現錯誤提示:

ERROR: rvm requires autoreconf to install the selected ruby interpreter however autoreconf was not found in the PATH

通過 Homebrew 安裝 automake 後,即可正常安裝 RVM:

安裝 automake
1
$ brew install automake

安裝 Octopress

接着就可以從 GitHub 獲取 Octopress 項目:

獲取 Octopress
1
$ git clone git://github.com/imathis/octopress.git octopress

由於 Ruby 早已出了新版本 1.9.3,而 Octopress 工程中設定要求版本是 1.9.2,所以這裡要解决一下,因爲 Lion 系統上最新的開發工具也是 Xcode 4.3。而也只有 1.9.3 可以和 Xcode 4.3 相容。 Octopress 在 1.9.3 也是正常工具的,所以這裡修改一下版本設定档案:

修正 Octopress 限制設定
1
$ echo rvm use 1.9.3 > octopress/.rvmrc

rake 版本可能也不相容,同樣可以修改 octopress/Gemfile.lock 档案中的 rake 版本設定。這裡如果繼續按照档案說明繼續安裝的話還可能會出現如下的錯誤提示:

Installing rb-fsevent (0.4.3) with native extensions … fsevent/fsevent_watch.c:1:10: fatal error: ‘stdio.h’ file not found #include

1 error generated. extconf.rb:59:in `’: Compilation of fsevent_watch failed (see README) (RuntimeError)

這裡可以提前修正一下,用xcode-select指令指定 Xcode 路徑。關於路徑這個問題,蘋果最後幾個版本變化比較大。過往的 Xcode 安裝是使用安裝嚮導程式,所以安裝路徑被默認設定到了/Developer,不過後來 Mac App Store 的開放, Xcode 現在也放在了 Mac App Store 上免費提供,經過了 4.2 版本的蹩腳安裝方式(先下載再進一步安裝),4.3 版本對 Xcode 的部署進行了修改,現在的 Xcode 基本也轉化成了複製/粘貼即可使用的獨立程式。所以過往所有的工具包都放到了 Xcode 的 resource 中。所以 4.3 路徑應該是:/Applications/Xcode.app/Contents/Developer/。但 rb-fsevent 要使用的是 SDK 位置,在上面的路徑中是找不到的。這裡要針對 rb-fsevent 的需求設定路徑值,可以使用下面的指令來處理:

修正 Xcode-Select 路徑
1
$ sudo xcode-select -switch /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/

接着就可以照着官方档案的說明繼續安裝了:

完成 Octopress 安裝
1
2
3
4
5
6
$ cd octopress    # If you use RVM, You'll be asked if you trust the .rvmrc file (say yes).
$ ruby --version  # Should report Ruby 1.9.2
$ gem install bundler
$ rbenv rehash    # If you use rbenv, $ rehash to be able to run the bundle command
$ bundle install
$ rake install

至此,Octopress 就安裝好了。接着就是配置部落格了。基本按照官方档案配置也就没什麽了。額外提及一下的是 Octopress 集成的留言服務是 DISQUS 提供的,需要到網站上注册了網站的短域名後,寫入配置档案中即可生效。我現在還在轉移所有的過往文章,最終肯定是要放在 VPS 上的,看樣子就是利用 rsync 伺服器了,以下有兩篇關於 rsync 的安裝與設定:

還是把部落格再格式化了

搬遷

其實一起都想爲自己的部落格換個新的系統,因爲 wordpress 不適合我的習慣。作爲半個程式員,我總是希望我寫的内容可以比較“乾淨”一些,也就是不要包含那些討厭的 HTML 代碼,倒不是說 HTML 不容易理解,只是寫完後全篇就變得比較噁心。到處都是些標籤和轉義字元,這一點着實讓人崩潰。我曾一度想要自己實現一套符合自己要求的格式,再用伺服器代碼在讀取時格式成 CSS 排版,但終止還是放棄了。

畢竟自己没那麽多時間搞這類東西(生計所迫),好在知道了 Octopress 這套系統,其實我知道這個套件,遠比開始使用要早。但那時僅知道 Octopress 要依賴 Ruby 環境,而手頭没有這樣的虛擬主機,所以也就遲遲没有進一步瞭解。直到最近被 Wordpress 逼瘋了,决定換文章管理系統的時候又想起了 Octopress 套件,細讀說明档案後才覺得相識恨晚。 Octopress 幾乎有所有我原本就想要的功能,不利用數據庫做無謂的查詢、非常易讀的排版文法(Markdown 文法)、對我來說常規且够用的第三方插件、全靜態站點内容、基於差異辨識的伺服端資料同步,所有的這些功能都好像是爲自己量身定做似的,不愧是自稱 Geek 的部落格系統(我倒不覺得自己有 Geek 傾向)。

再名

之前的部落格所用的虛擬主機反正也到期了,所以之後會使用新的 ISP ,我一起都很喜歡 HE.NET ,網路很快,也一起很穩定。不過現在我需要 VPS 來部署一些自己新學習後的習作,所以這次目標是 FreeBSD VPS ,我學的第一個類 Unix 系統就是 FreeBSD ,所以也就不管流行度還是選了這個。這個系統真的非常棒,剛好我也可以好好復習復習操作系統上的一些基本知識,與 CUI 交互指令集。

我一起不喜歡給部落格起名字,原因只是我在起名字方面其實是個缺乏創意的人,所以只好引了兩句我喜歡的經文做名,這樣也好,明道若昧,進道若退。那麽我這也算是無名若有了吧。

真正解決 Safari on Lion 不支持 PAC 檔的問題

自 Lion 發佈以來最煩心的事情之一,貌似就是 Safari 不能很好的支持 PAC 自動配置檔的工作了。如下圖,指定了本地的 PAC 檔案後,Safari 並不能按照預期的效果運作。

1.使用普通的本地路徑時,代理無法第一次

其實網路上似乎已經存在了一個解決方案。不過從我的角度來分析似乎那個方案是有問題的。網路上的方案是在本地建立一個 WWW 伺服器,然後把 PAC 檔案發佈到裡面。再把這個網路地址貼到自動配置檔的地址配置中即可。我嘗試過很多次都沒成功,原因不明。而且很多這樣配置的人同時還配置了 SOCKET 伺服器。這樣看來的話,似乎成功的人都有這麼配置,這麼一來其實瀏覽器可能是一直在用 SOCKET 伺服器在連線下載。這樣 PAC 檔案就沒有意義了。不管怎麼樣,這個解決方案對我來說實在是不太看好。

所以我進而尋找了其它出路,不知道是不是以前沒有注意到大家可以看到 Lion 中的程式都可以看到是否是運作於沙箱下的。這個東西最早我是在 BSD 系統上看到的。這裡才想起來 IOS 系統上的 Safari 程式也有著同樣的毛病。不知道是不是這回 Back To Mac ,連這個 Bug 也一起 Back 回來了。總之,有了思路就好解決了。

先找一份新的 PAC 檔案來用:

2.下載一個全新的 PAC 档案

接著,把這個檔案保存到 /Applications/Safari.app/Contents/Resources/ 這個路徑下,也就是 Safari 瀏覽器程式包裝器中的資源目錄下:

3.將 PAC 档案放入 SAFARI 瀏覽器程式的包裝器内部

再來就是自己寫出這個 PAC 中系統中的路徑來(由於檔案保存在了 Safari.app 中,所以通過瀏覽按鈕應該是無法找到這個檔案的,只能用手寫的),然後保存到系統的網路設定中。

4.在代理設定中寫入新的本地路徑

現在打開 PAC 會影響到的網址看看效果,已經可以正常工作了。如果之前有設定 SOCKET 伺服器的同學記得把配置去掉,免得 PAC 檔案設定做了無用功。

5.PAC 工作正常了

剛才提到的沙箱,可以在活動監視器中看到狀態。

6.Safari 在 SandBox 中運作

好了,如此這般後, Safari on Lion 上的 PAC 設定檔 Bug 就解決了。

Mac OSX Lion 10.7.2 的幾個常見補丁

還是那塊 P35 Neo2 FR 主機板,由於前輩們已經提供了一下比較完美的 DSDT 版本了。所以這次就不必重新開始打補丁。本來結合 /Extra 下的擴展檔案一起使用已經足夠了。不過本次 10.7.2 升級不少 N 卡都中招了,所以乾脆在打 N 卡補丁的時候也順便把其它的補丁一並打了。

一. 10.7.2 升級後 N 卡黑屏 遇到的人非常多,解決起來也很簡單,最簡單的就是用 10.7.0NVDAResman.kext 替換 /S/L/E 下的擴展檔。不過這個對於完美黨來說有點接受不了。那就要改 DSDT 了。 在 DSDT 中搜索下面的片段:

Error Contents
1
2
3
4
5
"device_type"
Buffer (0x0D)
{
    "NVDA,Geforce"
}

修改成:

Replace Contents
1
2
3
4
5
"device_type"
Buffer (0x0D)
{
    "NVDA,Parent"
}

保存並編譯後,用來重新引導計算機即可,這次就不用使用舊版系統的擴展檔。

PS:這倒也體現了在本機劃分系統安裝分區的好處,即使系統掛了,我們也仍可由變色龍引導到系統安裝環境中,將這個安裝環境作為維護環境使用,非常方便。

"DSDT with GTS450"

二.為 GTS450 等 Fermi 類顯卡打上 OpenCL 補丁 需要打補丁的檔案都位置下面這個路徑:

1
$ cd /System/Library/Extensions/GeForceGLDriver.bundle/Contents/MacOS/

使用十六進制編輯工具開啟 GeForceGLDriver

查找:

1
EB A8 83 F8 02 7C 15

02 替換為 03 ,結果為:

1
EB A8 83 F8 03 7C 15

查找:

1
78 E8 83 F8 02 7C 11

02 替換為 03 ,結果為:

1
78 E8 83 F8 03 7C 11

接著,編輯 libclh.dylib 查 找:

1
8B 87 1C 0C 00 00 89 06 8B 87 20 0C 00 00 89 02

替換為:

1
31 C0 FF C0 FF C0 89 06 31 C0 89 02 90 90 90 90

兩個檔案編輯完成後,保存。重新引導計算機後即可生效。以上僅對工作於 x86_64 模式的環境有效。

三.修正對 AHCI SATA 的識別問題 這個問題在 DSDT 工具中已經提供了相應的補丁,按照說明照做即可。不過對於 P35 Neo2 FR 主機板,我沒有完全這樣做,因為前輩們放出的 Lion 適應的 DSDT 已經非常好用了,想比較少的改動,從前一版前輩們提供的 Snow Leopard 適應的 DSDT 在系統中識別是正常的,所以這個問題也比較容易解決,通過對比兩個 DSDT 檔案的不同,發現在 LionDSDT 中少了如下這一段代碼:

DSDT patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Device (SATA)
{
    Method (_DSM, 4, NotSerialized)
    {
        Store (Package (0x02)
            {
                "device-id",
                Buffer (0x04)
                {
                    0x81, 0x26, 0x00, 0x00
                }
            }, Local0)
        DTGP (Arg0, Arg1, Arg2, Arg3, RefOf (Local0))
        Return (Local0)
    }
}

將 Device (SATA)節點中的內容添加到 DSDT 中即可識別正常。

四.SSD 固態硬碟的 Trim 特性補丁 Apple 的擴展程式中設定了僅對自己出品的 SSD 才能開啟 Trim 特性。網上也有人給出了補丁的方法:

1
2
3
4
5
6
7
8
9
$ cd /System/Library/Extensions/IOAHCIFamily.kext/Contents/PlugIns/IOAHCIBlockStorage.kext/Contents/MacOS/

$ sudo cp IOAHCIBlockStorage IOAHCIBlockStorage.original

$ sudo perl -pi -e 's|(\x52\x6F\x74\x61\x74\x69\x6F\x6E\x61\x6C\x00{1,20})[^\x00]{9}(\x00{1,20}\x51)|$1\x00\x00\x00\x00\x00\x00\x00\x00\x00$2|sg' IOAHCIBlockStorage

$ sudo kextcache -system-prelinked-kernel

$ sudo kextcache -system-caches

"AHCI and SSD Trim Fixed"

重新引導計算機後即顯示已經啟用了 Trim 特性。且被補丁的檔案也備份成了 IOAHCIBlockStorage.original ,出現問題的時候可以進入維護模式進行補救。

如果不想自己手工來處理也可以使用網路上的同學製作的補丁程式 Trim Enabler,另外提供兩篇內容相似的文章,以供參考:

How To: Enable TRIM Support For All SSDs in OS X Lion》 《在 Lion 中開啟 Trim 支援