[小北De编程手记] : Lesson 03 - Selenium For C# 之 元素定位
无论哪一种自动化测试的驱动框架(基于B/S,桌面应用,还是手机App)。都应当具有一套优秀的元素定位技术。通常的自动化测试流程也可以简单的归结为是一个从被测试程序中识别或是定位元素以及执行操作和验证元素的过程。这一篇我们就开始给大家介绍一下Selenium中是如何定位DOM元素的。本文将会介绍如下内容:
- Selenium DOM 主要的定位方式。
- Selenium 如何扩展元素定位方式。
- 辅助浏览器工具
(一)Selenium DOM主要定位方式
上一篇中,我们介绍了WebDriver 和 WebElement两个类型。他们都具有方法FindElement和FindElements。 这便是Selenium WebDriver的API提供给我们的元素定位方式。IWebDriver要求同时实现接口ISearchContext,元素查找的方法便是在这个接口中定义的:
1 public interface IWebDriver : ISearchContext, IDisposable 2 { 3 //省略部分Code... ... 4 }
1 namespace OpenQA.Selenium 2 { 3 // Summary: 4 // Defines the interface used to search for elements. 5 public interface ISearchContext 6 { 7 IWebElement FindElement(By by); 8 9 ReadOnlyCollection<IWebElement> FindElements(By by); 10 } 11 }
他们都会接受一个By类型的参数。该类型的官网定义如下所示,Selenium主要提供了以下几种方式定位元素:
- ID : 根据DOM元素的ID属性定位。
- Name : 根据DOM元素的Name属性定位。
- ClassName : 根据DOM元素的Class属性定位。
- TagName : 根据DOM元素的TagName定位。
- LinkText : 根据DOM元素(link)的文本内容定位。
- PartialLinkText : 根据DOM元素(link)的部分文本内容定位。
- CssSelector:根据CSS 选择器定位元素。
- XPath:使用XPath定位元素。
元素定位的调用方式如下:
1 IWebDriver driver = new FirefoxDriver (); 2 IWebElement element; 3 4 element = driver.FindElement(By.Id("ObjectID")); 5 element = driver.FindElement(By.Name("ObjectName")); 6 element = driver.FindElement(By.ClassName("ObjectClassName")); 7 element = driver.FindElement(By.TagName("ObjectTagText")); 8 element = driver.FindElement(By.LinkText("ObjectLinkText")); 9 element = driver.FindElement(By.PartialLinkText( "ObjectPartialLinkText")); 10 11 // Use css selector. 12 element = driver.FindElement(By.CssSelector( "CssSelector For Object")); 13 // Use xPath. 14 element = driver.FindElement(By.XPath("XPath For Object"));
下面简单的介绍一下DOM元素的ID,Name,ClassName... ...XPath,CssSelector都是些什么鬼? 当然,如果你是一个已经很熟悉这些概念的小伙伴就可以直接忽略这部分内容。关于DOM元素的基本概念和知识这里我就不详细的描述了,有兴趣的小伙伴可以到这个链接学习一下:http://www.runoob.com/html/html-tutorial.html。
简单的说基本的HTML元素(DOM元素)构成了网页的内容,每个元素都是以一个个DOM标签的形式表现出来的。下面是一个网页标签的结构。我标出了ID,TagName,ClassName,Name所对应了位置。
结合之前介绍的By Class提供的静态方法。我们就可以定位到对应的HTML元素的位置。说到这里,很多资料或是书本都会有这样的描述:“编码中,使用ID,Name,Class属性是定位元素的首选方法”。没错这些元素定位简单直接,而且理论上的执行效率较快。但是(请注意,我说了但是~~~),现实的情况是开发人员可能根本就没有为元素定义这些属性,或者实际的应用ID是自动随机生成的,Name和ClassName又不能准确的唯一定位,此刻我们就需要其他的方式来定位元素。这也是XPath和Css选择器的作用了,实际的工作中,这两种定位方式应当是伴随你的主要方式,so ... ... 好好了解一下还是很有必要的。关于XPath和Css选择器的语法已经超出了我们要讨论的问题,想了解的小伙伴可以网上找一下相关的资料,这里我就不多说了。下面我们可以看一下定位博客园首页导航的XPath:
1 var divMain = driver.FindElement(By.Id("main")); 2 var lnkHome = driver.FindElement(By.XPath(".//ul[@class='post_nav_block']/li[1]/a")); 3 var lnkEssence = driver.FindElement(By.XPath(".//ul[@class='post_nav_block']/li[2]/a")); 4 var lnkCandidate = driver.FindElement(By.XPath(".//ul[@class='post_nav_block']/li[3]/a")); 5 var lnkNews = driver.FindElement(By.XPath(".//ul[@class='post_nav_block']/li[4]/a"));
关于获取超链接元素的两个方法By.LinkText和By.PartialLinkText,简单明了,在此我就不多做介绍了。
(二)Selenium 如何扩展元素定位的方式
除了基本的定位方式之外,如果我们想拥有自定义的定位应该如何处理呢?比如,我们的测试过程中,我们想一次性获取到所有CSS样式是.btn的input标签应当如何处理?
Selenium本身的底层驱动是基于JS的,同时也为我们上层的使用者(测试CASE编写者或测试框架开发者)为提供了可以的执行自定义JS,并返回数据的方法。回顾一下上文中将到的核心对象WebDriver,都是继承自RemoteWebDriver。而RemoteWebDriver实现了IJavaScriptExecutor接口,该接口定义了执行JS的行为:
1 namespace OpenQA.Selenium 2 { 3 // Summary: 4 // Defines the interface through which the user can execute JavaScript. 5 public interface IJavaScriptExecutor 6 {
7 object ExecuteAsyncScript(string script, params object[] args); 8 object ExecuteScript(string script, params object[] args); 9 } 10 }
因此,我们可以利用如下方式来执行我们自定义的JS,略懂JavaScript的同学看到这里,貌似应该明白了什么。没错,你可以自由的翱翔了(定义任何你想要的定位逻辑,不仅仅是定位元素)。当然,这个只是Selenium提供的接口,真正的使用和企业级的封装有机会的话我会开一个新的系列为大家介绍,本节先介绍到这里。
1 IJavaScriptExecutor jsExecutor = driver as IJavaScriptExecutor ; 2 jsExecutor.ExecuteScript("return $('#elementID')");
(三)浏览器辅助工具
编程就像习武,功力深厚固然好,但总要有合手的兵器。接下来,为大家推荐一下元素定位可能会用到的工具:
如果你用的是Firefox浏览器,建议你下载Firebug和FirePath:
- Firebug拥有很多功能(元素定位,脚本调试,网络监控 等等),可以帮你轻松的定位元素和观察DOM结构。
- FirePath理论上可以用来生成元素的XPath或是验证XPath的定位效果。(虽然工具可以生成XPath也不要指望靠他生成,还是要好好学习XPath的... ... 因为,工具生成的结果往往不是你想要的)。
如果你用的是Chrome或是IE浏览器,他们都有内置的开发者工具。
关于XPath的验证步骤,请参考下图(输入Xpath>点击Eval>查看定位到的元素):
(四)Demo
说了这么多,又到了做Demo时候了。so... 同样做了个简单的Demo供大家参考。Code上传到Github地址是:https://github.com/DemoCnblogs/Selenium,本节的Demo是用来验证了博客园首页的导航栏内的文字是否正确,使用了几种方式获取DOM元素,代码如下:
1 using OpenQA.Selenium; 2 using OpenQA.Selenium.Firefox; 3 using System.Collections.Generic; 4 using Xunit; 5 using Xunit.Abstractions; 6 7 namespace Demo.SeleniumTest 8 { 9 public class Lesson03_FindElement 10 { 11 /// <summary> 12 /// 输出对象 13 /// </summary> 14 private readonly ITestOutputHelper _output; 15 /// <summary> 16 /// 构造函数,初始化输出对象 17 /// </summary> 18 /// <param name="output">注入输出对象</param> 19 public Lesson03_FindElement(ITestOutputHelper output) 20 { 21 this._output = output; 22 } 23 24 /// <summary> 25 /// demo1 : 获取元素 26 /// </summary> 27 [Fact(DisplayName = "Cnblogs.CheckNavBar.Demo1")] 28 public void CheckNavBar_GetElement() 29 { 30 _output.WriteLine("Step 01 : 启动浏览器并打开博客园首页。"); 31 IWebDriver driver = new FirefoxDriver(); 32 driver.Url = "http://www.cnblogs.com"; 33 34 _output.WriteLine("Step 02 : 寻找需要检查的页面元素。"); 35 var divMain = driver.FindElement(By.Id("main")); 36 var lnkHome = driver.FindElement(By.XPath(".//ul[@class='post_nav_block']/li[1]/a")); 37 var lnkEssence = driver.FindElement(By.XPath(".//ul[@class='post_nav_block']/li[2]/a")); 38 var lnkCandidate = driver.FindElement(By.XPath(".//ul[@class='post_nav_block']/li[3]/a")); 39 var lnkNews = driver.FindElement(By.XPath(".//ul[@class='post_nav_block']/li[4]/a")); 40 41 _output.WriteLine("Step 03 : 检查导航条文字信息。"); 42 Assert.Equal<string>("首页", lnkHome.Text); 43 Assert.Equal<string>("精华", lnkEssence.Text); 44 Assert.Equal<string>("候选", lnkCandidate.Text); 45 Assert.Equal<string>("新闻", lnkNews.Text); 46 47 _output.WriteLine("Step 04 : 关闭浏览器。"); 48 driver.Close(); 49 } 50 51 52 [Fact(DisplayName = "Cnblogs.CheckNavBar.Demo2")] 53 public void CheckNavBar_GetElements() 54 { 55 _output.WriteLine("Step 00 : 准备测试数据。"); 56 var testDatas = new List<string>() { "首页", "精华", "候选", "新闻" }; //准备测试数据 57 58 _output.WriteLine("Step 01 : 启动浏览器并打开博客园首页。"); 59 IWebDriver driver = new FirefoxDriver(); 60 driver.Url = "http://www.cnblogs.com"; 61 62 _output.WriteLine("Step 02 : 寻找需要检查的页面元素。"); 63 var divMain = driver.FindElement(By.Id("main")); 64 var lnkNavList = driver.FindElements(By.XPath(".//ul[@class='post_nav_block']/li[1]/a")); 65 66 _output.WriteLine("Step 03 : 检查导航条文字信息。"); 67 for (var i = 0; i < lnkNavList.Count; i++) 68 { 69 Assert.Equal<string>(testDatas[i], lnkNavList[i].Text); 70 } 71 _output.WriteLine("Step 04 : 关闭浏览器。"); 72 driver.Close(); 73 } 74 } 75 }
总结:本文主要介绍了以下几点内容。
- Selenium元素定位方式(ID,Name,ClassName,TagName,XPath,Css选择器等等)。
- 如何扩展Selenium,并自定义定位方式
- 推荐了一些辅助工具
关于《Selenium For C#》 系列,我计划给大家逐一介绍一些Selenium Driver的基础知识和框架的扩展点。 当然,之后会有更多关于测试框架构以及软件构建方面的文章。愿我主保佑我有时间做完这件事情... ...
《Selenium For C#》的相关文章:Click here.
- [小北De编程手记] : Lesson 01 - Selenium For C# 之 环境搭建
- [小北De编程手记] : Lesson 02 - Selenium For C# 之 核心对象
- [小北De编程手记] : Lesson 03 - Selenium For C# 之 元素定位
- [小北De编程手记] : Lesson 04 - Selenium For C# 之 API 上
- [小北De编程手记] : Lesson 05 - Selenium For C# 之 API 下
- [小北De编程手记] : Lesson 06 - Selenium For C# 之 流程控制
- [小北De编程手记] : Lesson 07 - Selenium For C# 之 窗口处理
- [小北De编程手记] : Lesson 08 - Selenium For C# 之 PageFactory & 团队构建
说明:Demo地址:https://github.com/DemoCnblogs/Selenium