上一篇,咱们介绍了一些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