自動化測試如此容易!多語言自動化測試框架 Selenium 編程(C#篇)

介紹

Selenium 官網:https://www.selenium.dev/

Selenium 是功能強大的自動化測試工具集,是支持 Web 瀏覽器自動化的一系列工具和庫的總括項目,一共包括以下三個項目:

  • Selenium WebDriver
  • Selenium IDE
  • Selenium Grid

Selenium 的核心是 WebDriver,可以在許多瀏覽器中交換運行,WebDriver 以原生的方式驅動瀏覽器,。

WebDriver 架構設計如下:
對每種瀏覽器編寫一個 Driver,如 ChromeDriver,這是操作瀏覽器的驅動,對外提供了各類操作接口。Selenium 設計了 WebDriver 抽象,以便通過統一的抽象使用各類瀏覽器驅動。

file

或者還可以遠程訪問接口:

file

下面筆者介紹在 C# 中如何使用 Selenium WebDriver 編寫自動化測試程序。

安裝依賴

創建一個 C# 控制檯項目,首先安裝依賴包 Selenium.WebDriver,這個庫提供了瀏覽器驅動接口的基礎 API 和統一抽象。

Selenium.WebDriver

接着,安裝瀏覽器對應的驅動實現:

Selenium.WebDriver.ChromeDriver

只要搜索 Selenium.WebDriver 即可,然後根據瀏覽器補充後綴,下載對應的瀏覽器驅動。

第一個 demo

打開:https://www.selenium.dev/selenium/web/web-form.html

這個地址是官方用於測試的頁面,裏面有比較多的 html 組件,足夠我們學習使用。

file

下面這個示例中,包括了打開頁面、查找元素、填充內容和獲取信息的代碼,讀者可以運行這段代碼從中瞭解編寫自動化測試程序的基本執行流程,更多的細節將在後面的小節中講解。

using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;

class Program
{
	static void Main()
	{
        // 使用 ChromeDriver 驅動
		IWebDriver driver = new ChromeDriver();
		
		// 啓動的時候打開這個頁面
		driver.Navigate().GoToUrl("https://www.selenium.dev/selenium/web/web-form.html");
		
		// 獲取頁面信息
		var title = driver.Title;
		// 隱式等待,頁面元素不會立馬出現,需要單獨一段時間
		driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromMilliseconds(500);
		// 搜索元素
		var textBox = driver.FindElement(By.Name("my-text"));
		var submitButton = driver.FindElement(By.TagName("button"));
		
		// 往輸入框填充文本
		textBox.SendKeys("Selenium");
		// 點擊提交按鈕
		submitButton.Click();
		
		// 點擊提交按鈕之後,頁面會刷新,此時獲取的是跳轉之後的頁面的元素
		var message = driver.FindElement(By.Id("message"));
		var value = message.Text;
		
		// 退出
		driver.Quit();
	}
}

注意:demo 程序啓動時,會啓動 Chrome 瀏覽器,如果啓動瀏覽器太慢,demo 程序會報錯退出。

因此需要先啓動 Chrome 瀏覽器,再啓動 demo 程序,以便減少 Chrome 瀏覽器新窗口的啓動時間。

demo 程序啓動後,會自動填充表單和提交,接着跳轉到新的頁面。

file

頁面加載策略

頁面開發模式有多種多樣,如 PHP、asp 這種一體式開發,如服務器渲染然後返回整個頁面、前後端分離先加載靜態資源然後從後端 API 中加載數據生成頁面。

很多時候,頁面不會短時間完成渲染,有些頁面元素需要一段時間後才能出現。在使用 WebDriver 的時候,我們也可以根據需求決定在什麼時候啓動自動化操作。

頁面有三種基本加載策略:

策略 就緒狀態 備註
normal complete 默認值,,等待所有資源下載
eager interactive DOM 訪問已準備就緒, 但諸如圖像的其他資源可能仍在加載。
none Any 完全不會阻塞 WebDriver,WebDriver 僅等待初始頁面已下載。

如果由於下載對自動化不重要的資源(例如, 圖像、css、js) 而需要很長時間才能加載頁面,,可以將默認參數 normal 更改爲 eagernone 以加快會話加載速度。

設置方法:

var chromeOptions = new ChromeOptions();
chromeOptions.PageLoadStrategy = PageLoadStrategy.Normal;
IWebDriver driver = new ChromeDriver(chromeOptions);

另外,WebDriver 提供了三種方式等待頁面元素的出現:

  • 顯式等待

  • 隱式等待

  • 流暢等待

我們可以使用等待來讓 findElement 調用等待直到腳本中動態添加的元素被添加到DOM中:

WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
IWebElement firstResult = wait.Until(e => e.FindElement(By.XPath("//a/h3")));

這種方法稱爲顯式等待

WebDriver 會等待路徑 //a/h3 的元素出現,最大等待時間爲 10s。

而通過隱式等待,WebDriver 在試圖查找_任何_元素時在一定時間內輪詢DOM。當網頁上的某些元素不是立即可用並且需要一些時間來加載時是很有用的。

隱式等待是告訴 WebDriver 如果在查找一個或多個不是立即可用的元素時輪詢 DOM 一段時間。一旦設置好,隱式等待就被設置爲會話的生命週期。

設置隱式等待的輪詢時間:

driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromMilliseconds(500);

警告: 不要混合使用隱式和顯式等待。這樣做會導致不可預測的等待時間。例如,將隱式等待設置爲10秒,將顯式等待設置爲15秒,可能會導致在20秒後發生超時。

流暢等待 定義了等待條件的最大時間量,以及檢查條件的頻率。

用戶可以配置等待來忽略等待時出現的特定類型的異常,例如在頁面上搜索元素時出現的NoSuchElementException

WebDriverWait wait = new WebDriverWait(driver, timeout: TimeSpan.FromSeconds(30))
{
	PollingInterval = TimeSpan.FromSeconds(5),
};

代理

代理服務器充當客戶端和服務器之間的請求中介,使用代理服務器用於 Selenium 的自動化腳本, 可能對以下方面有益:

  • 捕獲網絡流量
  • 模擬網站後端響應
  • 在複雜的網絡拓撲結構或嚴格的公司限制/政策下訪問目標站點.

如果在公司環境中,或者需要開啓飛機上網,瀏覽器無法連接到 URL,則需要藉助代理進行訪問。

Selenium WebDriver 提供瞭如下設置代理的方法,代碼示例如下:

using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;

class Program
{
	static void Main()
	{   		
		ChromeOptions options = new ChromeOptions();
		
		Proxy proxy = new Proxy();
		proxy.Kind = ProxyKind.Manual;
		proxy.IsAutoDetect = false;
		proxy.SslProxy = "<HOST:PORT>";
		options.Proxy = proxy;
		options.AddArgument("ignore-certificate-errors");
		
		IWebDriver driver = new ChromeDriver(options);
		driver.Navigate().GoToUrl("https://www.selenium.dev/");
	}
}

瀏覽器版本

例如, 假設想使用 Chrome 版本 67 在 Windows XP 上運行 Chrome:

var chromeOptions = new ChromeOptions();

chromeOptions.BrowserVersion = "67";
chromeOptions.PlatformName = "Windows XP";

元素操作

元素操作主要分爲下面這幾種:

  • 文件上傳

  • 查詢網絡元素:根據提供的定位值定位元素

  • Web元素交互:用於操縱表單的高級指令集

  • 定位策略:在 DOM中 標識一個或多個特定元素的方法

  • 元素的信息:html 元素的屬性

下面來介紹不同 html 元素的操作方法示例。

文件上傳

file

上傳文件實際上是在 type=fileinput 標籤中,填寫本地路徑的文件地址,這個地址需要填寫文件的絕對路徑。

using System;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;

namespace SeleniumDocumentation.SeleniumPRs
{
	class FileUploadExample
	{
		static void Main(String[] args)
		{
			IWebDriver driver = new ChromeDriver();
			try
			{
				// Navigate to Url
				driver.Navigate().GoToUrl("https://www.selenium.dev/selenium/web/web-form.html");
				// 文件路徑一定是可以存在的,不能亂填,建議絕對路徑
				driver.FindElement(By.Name("my-file")).SendKeys("D:/Desktop/images/學習.jpg");
				var submitButton = driver.FindElement(By.TagName("button"));
				
				submitButton.Click();
				
				if (driver.PageSource.Contains("File Uploaded!"))
				{
					Console.WriteLine("file uploaded");
				}
				else
				{
					Console.WriteLine("file not uploaded");
				}

				driver.Quit();
			}
			catch (Exception ex)
			{
				Console.WriteLine(ex);
			}
		}
	}
}

查找元素

在 WebDriver 中有 8 種不同的內置元素定位策略:

定位器 Locator 描述
class name 定位class屬性與搜索值匹配的元素(不允許使用複合類名)
css selector 定位 CSS 選擇器匹配的元素
id 定位 id 屬性與搜索值匹配的元素
name 定位 name 屬性與搜索值匹配的元素
link text 定位link text可視文本與搜索值完全匹配的錨元素
partial link text 定位link text可視文本部分與搜索值部分匹配的錨點元素。如果匹配多個元素,則只選擇第一個元素。
tag name 定位標籤名稱與搜索值匹配的元素
xpath 定位與 XPath 表達式匹配的元素

下面是查找元素的用例:

// 通過 id 或 name
IWebElement vegetable = driver.FindElement(By.ClassName("tomatoes"));
IWebElement fruits = driver.FindElement(By.Id("fruits"));
IWebElement fruit = fruits.FindElement(By.ClassName("tomatoes"));

// 通過 css 選擇器
var fruit = driver.FindElement(By.CssSelector("#fruits .tomatoes"));

// 返回多個元素
IReadOnlyList<IWebElement> plants = driver.FindElements(By.TagName("li"));

獲取當前頁面的焦點在哪個元素:

var element = driver.SwitchTo().ActiveElement();
string attr = element.GetAttribute("title");

file

file

頁面元素交互

僅有五種基本命令可用於元素的操作:

  • 點擊 (適用於任何元素)
  • 發送鍵位 (僅適用於文本字段和內容可編輯元素,.SendKeys())
  • 清除 (僅適用於文本字段和內容可編輯元素)
  • 提交 (僅適用於表單元素)(在Selenium 4中不再建議使用)
  • 選擇(查找元素)
點擊

可以觸發元素的點擊事件:

var submitButton = driver.FindElement(By.TagName("button"));
submitButton.Click();
輸入

元素髮送鍵位命令,即 .SendKeys() ,這個方法對可編輯的元素都通用,如 input、select 等元素。

driver.FindElement(By.Name("my-file")).SendKeys("D:/Desktop/images/學習.jpg");
清除

對於可編輯文本或具有輸入的元素,如文本域、選擇框、文件上傳框的,可以清除元素當前的value 屬性。

IWebElement searchInput = driver.FindElement(By.Name("q"));
searchInput.SendKeys("selenium");
// Clears the entered text
searchInput.Clear();

獲取元素屬性

  • 是否顯示
  • 是否啓用
  • 是否被選定
  • 獲取元素標籤名
  • 位置和大小
  • 獲取元素CSS值
  • 文本內容
  • 獲取特性或屬性

在 JS 中,我們可以這樣獲取一個元素的值或其它屬性:

document.getElementById("my-text-id").value
"111111111"

在 WebDriver 中可以通過 IWebElement 接口的 字段/屬性 獲取元素屬性,但不多:

Boolean is_email_visible = driver.FindElement(By.Name("email_input")).Displayed;

其它需要的屬性可以通過 GetAttribute 等方法獲取,如:

string attr = element.GetAttribute("title");

IWebElement 的定義如下:

  public interface IWebElement : ISearchContext
  {
    string TagName { get; }
    string Text { get; }
    bool Enabled { get; }
    bool Selected { get; }
    Point Location { get; }
    Size Size { get; }
    bool Displayed { get; }
    void Clear();
    void SendKeys(string text);
    void Submit();
    void Click();
    string GetAttribute(string attributeName);
    string GetDomAttribute(string attributeName);
    string GetDomProperty(string propertyName);
    string GetCssValue(string propertyName);
    ISearchContext GetShadowRoot();
  }

瀏覽器頁面

對於瀏覽器頁面的操作,無外乎下面四種:

  • 打開網站

  • 後退

  • 前進

  • 刷新

示例代碼也很簡單:

// 打開
driver.Navigate().GoToUrl(@"https://selenium.dev");
// 後退
driver.Navigate().Back();
// 前進
driver.Navigate().Forward();
// 刷新
driver.Navigate().Refresh();

用戶登錄憑證

目前只發現了使用 Basic、Cookie 兩種登錄認證方式, JWT Token 這種需要設置 Header 頭的方式找不到實現。

下面是使用 Cookie 打開網頁的示例:

			var chromeOptions = new ChromeOptions();
			IWebDriver driver = new ChromeDriver(chromeOptions);
			
			try
			{
				driver.Navigate().GoToUrl("https://www.google.com");
				// Adds the cookie into current browser context
				driver.Manage().Cookies.AddCookie(new Cookie("key", "value"));
				
				driver.FindElement(By.CssSelector("[name='q']")).SendKeys("webElement");
				// Get attribute of current active element
				var btnK = driver.FindElement(By.Name("btnK"));
				btnK.Click();
			}
			finally
			{
				driver.Quit();
			}

關於使用 C# 開發 Selenium WebDriver 的教程就到這裏,讀者可到官方文檔瞭解更多。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章