上一篇,咱們介紹了一些Selenium WebDriver相關的API,下面咱們就接着上一篇繼續介紹Selenium經常使用的API,這一篇的內容主要涉及到如下話題:html
首先,咱們試想一下這樣的場景。待測試的系統支持一些組合鍵的操做,例如:按住Ctrl的同時點擊某個表格的某個單元格,該數據行會高亮顯示。要模擬這樣的操做,咱們應該怎麼處理呢?Selenium WebDriver的API爲咱們提供了一個Actions類,使得咱們能夠模擬用戶複雜的操做。我先列出一個測試剛纔描述場景的測試用例實現:git
1 //Step 01 : 啓動瀏覽器並打開某個站點的首頁。 2 var driver = new FirefoxDriver(); 3 driver.Url = "http://www.xxx.com"; 4 5 //Step 02 : 尋找須要操做的表格單元格。 6 var tableCol = driver.FindElement(By.XPath("//table[@id='tblTest']/tbody/tr/td[1]")); 7 var action = new Actions(driver); 8 action.KeyDown(Keys.Control); 9 action.Click(tableCol); 10 action.Build(); 11 action.Perform();
上面代碼的Step02展現瞭如何利用Actions對象構建複雜的操做,值得注意的是當調用Actions對象的操做方法(即Click和KeyDown)時並無真正的執行你想要的操做,而是當Perform被調用的時候才真正的執行一些列的操做。另外,Actions類全部的操做方法都是自引用的。所以,咱們能夠用連續調用的方式更簡潔的完成操做。(說明:自引用的概念是編程大師C++之父 「比亞尼·斯特朗斯特魯普」 在《The C++ Programming Language》中最先提出的,就是一個對象的某個方法調用結束以後返回該對象自己的一種編程方式),所以以前的代碼等價於:github
1 //Step 01 : 啓動瀏覽器並打開某個站點的首頁。 2 var driver = new FirefoxDriver(); 3 driver.Url = "http://www.xxx.com"; 4 5 //Step 02 : 尋找須要操做的表格單元格。 6 var tableCol = driver.FindElement(By.XPath("//table[@id='tblTest']/tbody/tr/td[1]")); 7 var action = new Actions(driver); 8 action.KeyDown(Keys.Control).Click(tableCol).Build().Perform();
下面我簡單的羅列一下Actions類經常使用的方法:編程
這些函數的聲明以下:瀏覽器
關於上述操做,仍是照例給你們作了個Demo。打開博客園首頁實現選中「代碼改變世界」的效果,選中自己意義不大,這裏只是展現一下Selenium的操做粒度能夠細到一個怎麼樣的級別。代碼以下:緩存
1 /// <summary> 2 /// demo4 : 複雜交互 3 /// </summary> 4 [Fact(DisplayName = "Cnblogs.SeleniumAPI.Demo4")] 5 public void SeleniumAPI_Demo4() 6 { 7 _output.WriteLine("Step 01 : 啓動瀏覽器並打開博客園首頁。"); 8 IWebDriver driver = new FirefoxDriver(); 9 driver.Url = "http://www.cnblogs.com"; 10 11 _output.WriteLine("Step 02 : 尋找須要操做的頁面元素。"); 12 var divText = driver.FindElement(By.Id("site_nav_top")); 13 var point = divText.Location; 14 var width = int.Parse(divText.GetCssValue("width").Replace("px", string.Empty)); 15 16 _output.WriteLine("Step 03 : 選中文本信息。"); 17 var action = new Actions(driver); 18 action 19 .MoveByOffset(point.X, point.Y) //移動鼠標到文本開頭 20 .ClickAndHold() //按下鼠標 21 .MoveByOffset(point.X + width, point.Y) //移動鼠標到文本結束 22 .Release() //釋放鼠標 23 .Build() 24 .Perform(); 25 26 System.Threading.Thread.Sleep(5000); 27 _output.WriteLine("Step 04 : 關閉瀏覽器。"); 28 driver.Close(); 29 }
運行結果以下圖所示,咱們能夠看到首頁上的文字已經被選中:架構
對於常見的按鈕,輸入框,超連接等元素,以前的Demo已經有不少相關的演示了,大多數對DOM元素的操做也都是點擊,輸入文本,獲取值... ... 這些操做IWebElement中都有相關的定義,我以前的文章《Lesson 02 - Selenium For C# 之 核心對象》裏有相關的介紹,這裏就再也不贅述了。這一部分,咱們主要介紹一下特殊的DOM元素以及處理方式。框架
下拉菜單是一種很常見的DOM元素,它不一樣於文本框、按鈕這樣的元素(一個標籤就能夠描述)。而是由多個標籤組成的,其結構以下圖所示:編程語言
那麼在Selenium中咱們應該如何處理呢?針對Select標籤,Selenium提供了一個專門的類來處理。聲明以下:ide
1 // Summary: 2 // Provides a convenience method for manipulating selections of options in an 3 // HTML select element. 4 public class SelectElement : IWrapsElement 5 { 6 // Summary: 7 // Gets all of the selected options within the select element. 8 public IList<IWebElement> AllSelectedOptions { get; } 9 // 10 // Summary: 11 // Gets a value indicating whether the parent element supports multiple selections. 12 public bool IsMultiple { get; } 13 // 14 // Summary: 15 // Gets the list of options for the select element. 16 public IList<IWebElement> Options { get; } 17 18 public IWebElement SelectedOption { get; } 19 20 public void DeselectAll(); 21 22 public void DeselectByIndex(int index); 23 24 public void DeselectByText(string text); 25 26 public void DeselectByValue(string value); 27 28 public void SelectByIndex(int index); 29 30 public void SelectByText(string text); 31 32 public void SelectByValue(string value); 33 }
SelectElement常見的操做方法和屬性以下:
實在是找不的一個下拉菜單,so... ...只能簡單的寫一下如何使用了,下面的Demo中展現瞭如何轉化並獲得SelectElement對象並進行相關的操做。還有一點值得說明的是xUnit.Net中當設置Fact標籤的Skip屬性時,這個case在運行時是會被Runner忽略掉的,代碼以下:
1 /// <summary> 2 /// demo5 : SelectElement 3 /// </summary> 4 [Fact(DisplayName = "Cnblogs.SeleniumAPI.Demo5", Skip = "Just Demo")] 5 public void SeleniumAPI_Demo5() 6 { 7 _output.WriteLine("Step 01 : 啓動瀏覽器並打開某個網站。"); 8 IWebDriver driver = new FirefoxDriver(); 9 driver.Url = "http://www.xxx.com"; 10 11 _output.WriteLine("Step 02 : 尋找須要操做的頁面元素。"); 12 var dllDom = (SelectElement)driver.FindElement(By.Id("selectDomId")); 13 var isMultiple = dllDom.IsMultiple; 14 var option = dllDom.SelectedOption; 15 dllDom.SelectByIndex(1); 16 dllDom.SelectByText("Text"); 17 dllDom.SelectByValue("Value"); 18 19 _output.WriteLine("Step 03 : 關閉瀏覽器。"); 20 driver.Close(); 21 }
這裏須要說明的另外一種DOM元素是單選按鈕,其實在處理單選按鈕的時候和其餘的IWebElement元素是一致的。都是使用IWebElement定義的Click方法點擊,用Selected屬性獲取元素的選中狀態。那爲何我要把這個元素單獨提出講解呢?緣由就是單選按鈕每每是一組只能有一個被選中。對於這樣的元素狀態咱們要特別注意。如:頁面上有A,B,C三個單選按鈕,默認A會被選中,此時你執行下面的代碼就可能會引起異常(Selenium會告知你A元素狀態已經改變須要從新加載)。
1 var radioA = driver.FindElement(By.Id("radioA_Id")); 2 var radioB = driver.FindElement(By.Id("radioB_Id")); 3 radioB.Click(); 4 var isSelected = radioA.Selected; // 拋出異常:元素已經改變
其實,Selenium中咱們常常須要處理某個已經緩存元素髮生變化的狀況。至於相關的最佳實踐,我會在後續的文章中介紹,本文主要是講解一些基礎的操做。
對於不熟悉HTML的同窗(說明一下,作B/S自動化 HTML是必須會的,so....仍是要好好了解一下的),在此附上單選按鈕的DOM結構實例:
企業級的測試框架大多都會在測試CASE失敗的時候對當前的UI進行截圖,以方便測試人員定位Test Case失敗的緣由。這裏我就來專門介紹一下Selenium 提供的截圖功能,以前咱們提到過咱們使用的WebDriver繼承自RemoteWebDriver。而RemoteWebDriver實現的不少的功能接口,好比以前咱們所提到的IJavaScriptExecutor接口。ITakesScreenshot接口定義了獲取屏幕截圖方法,一樣RemoteWebDriver實現了這個接口,也就是說咱們能夠利用WebDriver對象來獲取屏幕的截圖。ITakesScreenshot的定義以下:
1 namespace OpenQA.Selenium 2 { 3 // Summary: 4 // Defines the interface used to take screen shot images of the screen. 5 public interface ITakesScreenshot 6 { 7 // Summary: 8 // Gets a OpenQA.Selenium.Screenshot object representing the image of the page 9 // on the screen. 10 // 11 // Returns: 12 // A OpenQA.Selenium.Screenshot object containing the image. 13 Screenshot GetScreenshot(); 14 } 15 }
下面咱們就來看看如何實現截圖的功能,咱們重寫了以前的一個Demo,打開博客園首頁搜索「小北De編程手記」。這一次,添加了截圖查詢結果頁面的功能,並把圖片保存到了當前的執行目錄下,使用ITakesScreenshot.GetScreenshot獲取Selenium提供的截屏對象,並保存截屏圖片到本地文件:
1 /// <summary> 2 /// demo6 : 截屏 3 /// </summary> 4 [Fact(DisplayName = "Cnblogs.SeleniumAPI.Demo6")] 5 public void SeleniumAPI_Demo6() 6 { 7 _output.WriteLine("Step 01 : 啓動瀏覽器並打開博客園首頁。"); 8 IWebDriver driver = new FirefoxDriver(); 9 driver.Url = "http://www.cnblogs.com"; 10 11 _output.WriteLine("Step 02 : 尋找須要操做的頁面元素。"); 12 var txtSearch = driver.FindElement(By.Id("zzk_q")); 13 var btnSearch = driver.FindElement(By.XPath(".//input[@type='button' and @value='找找看']")); 14 15 _output.WriteLine("Step 03 : 輸入查詢文本&點擊查詢"); 16 txtSearch.SendKeys("小北De編程手記"); 17 btnSearch.Click(); 18 19 _output.WriteLine("Step 04 : 截屏"); 20 var takesScreenshot = (ITakesScreenshot)driver; 21 var screenshot = takesScreenshot.GetScreenshot(); 22 screenshot.SaveAsFile("screenshot.png", ImageFormat.Png); 23 24 _output.WriteLine("Step 05 : 關閉瀏覽器。"); 25 driver.Close(); 26 }
代碼運行完畢以後,查看本地目錄,能夠找到剛剛保存的文件:
最後,仍是要給你們提一下關於如何擴展Selenium API的功能,這個部分我會在其餘的關於自動化測試框架構建的系列中詳細描述,在這裏只是簡單的提一下框架預留的接口IJavaScriptExecutor,以前的文章《Lesson 03 - Selenium For C# 之 元素定位》對這個接口有一個簡要的介紹。這裏再次說起,主要有兩個緣由:
第一,該接口能夠很好的發揮Javascript的能力,若是結合C#自己的功能(固然你也能夠用Java,Ruby等其餘Selenium支持的編程語言)能夠幫助讓你的自動化測試框架具備不少很酷的功能(例如:控制瀏覽器滾動條,更簡單的讀取表格元素... ...)。
第二,Selenium有着和優雅的設計,WebDriver還實現了許許多多其餘的接口,IJavaScriptExecutor 和 ITakesScreenshot也只是其中的一部分。每一個接口都有特定的能力。這些每每是通常的自動化測試用例編寫人員不須要關心的地方,但若是你是一個測試框架的架構師或是一個打算構建本身的測試框架的小夥伴。那麼瞭解這些接口是你的必經之路。
關於《Selenium For C#》 系列,我計劃給你們逐一介紹一些Selenium Driver的基礎知識和框架的擴展點。 固然,以後會有更多關於測試框架構以及軟件構建方面的文章。願我主保佑我有時間作完這件事情... ...
《Selenium For C#》的相關文章:Click here.
說明:Demo地址:https://github.com/DemoCnblogs/Selenium