介绍

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

Selenium 是功能强大的自动化测试工具集,是支持 Web 浏览器自动化的一系列工具和库的总括项目,一共包括以下三个项目:

  • Selenium WebDriver
  • Selenium IDE
  • Selenium Grid

Selenium 的核心是 WebDriver,可以在许多浏览器中交换运行,WebDriver 以原生的方式驱动浏览器,。

WebDriver 架构设计如下:

对每种浏览器编写一个 Driver,如 ChromeDriver,这是操作浏览器的驱动,对外提供了各类操作接口。Selenium 设计了 WebDriver 抽象,以便通过统一的抽象使用各类浏览器驱动。

或者还可以远程访问接口:

下面笔者介绍在 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 组件,足够我们学习使用。

下面这个示例中,包括了打开页面、查找元素、填充内容和获取信息的代码,读者可以运行这段代码从中了解编写自动化测试程序的基本执行流程,更多的细节将在后面的小节中讲解。

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 程序启动后,会自动填充表单和提交,接着跳转到新的页面。

页面加载策略

页面开发模式有多种多样,如 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 元素的操作方法示例。

文件上传

上传文件实际上是在 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");

页面元素交互

仅有五种基本命令可用于元素的操作:

  • 点击 (适用于任何元素)
  • 发送键位 (仅适用于文本字段和内容可编辑元素,.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 的教程就到这里,读者可到官方文档了解更多。

自动化测试如此容易!多语言自动化测试框架 Selenium 编程(C#篇)的更多相关文章

  1. Android 框架式编程 —— 起篇

    一般的,在开发的时候,写过的代码在需求变更后,发现需要改动非常多的地方,那么说明之前的代码的架构肯定是存在问题的. 下面我们结合面向对象的六大基本原则谈Android 框架式编程.首先先介绍一下面向对 ...

  2. RobotFramework自动化测试框架-Selenium Web自动化(二)关于在RobotFramework中如何使用Selenium很全的总结(上)

    好久没有继续分享关于自动化测试相关的东西了,自动化在现今的测试领域已经越来越重要了,大部分公司在测试岗位招聘中都需要会相关的自动化测试知识.而 RobotFramework自动化测试框架 是自动化测试 ...

  3. RobotFramework自动化测试框架-Selenium Web自动化(三)关于在RobotFramework中如何使用Selenium很全的总结(下)

    本文紧接着RobotFramework自动化测试框架-Selenium Web自动化(二)关于在RobotFramework中如何使用Selenium很全的总结(上)继续分享RobotFramewor ...

  4. 《Selenium 2自动化测试实战 基于Python语言》中发送最新邮件无内容问题的解决方法

    虫师的<Selenium 2自动化测试实战 基于Python语言>是我自动化测试的启蒙书 也是我推荐的自动化测试入门必备书,但是书中有一处明显的错误,会误导很多读者,这处错误就是第8章自动 ...

  5. 小白学 Python 爬虫(28):自动化测试框架 Selenium 从入门到放弃(下)

    人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...

  6. 《Selenium2自动化测试实战--基于Python语言》 --即将面市

    发展历程: <selenium_webdriver(python)第一版>   将本博客中的这个系列整理为pdf文档,免费. <selenium_webdriver(python)第 ...

  7. 关于《Selenium3自动化测试实战--基于python语言》

    2016年1月,机缘巧合下我出版了<Selenium2自动化测试实战--基于python语言>这本书,当时写书的原因是,大部分讲Selenium的书并不讲编程语言和单元测试框,如果想在项目 ...

  8. selenium2自动化测试实战--基于Python语言

    自动化测试基础 一. 软件测试分类 1.1 根据项目流程阶段划分软件测试 1.1.1 单元测试 单元测试(或模块测试)是对程序中的单个子程序或具有独立功能的代码段进行测试的过程. 1.1.2 集成测试 ...

  9. 移动端自动化测试(一)之 Appium+Pyhton环境准备篇

    移动端自动化测试(一)之 Appium+Pyhton环境准备篇 2016-11-17 16:51 by CockRoacher, 5046 阅读, 1 评论, 收藏, 编辑 由于工作的需要进行Andr ...

  10. 手机自动化测试:搭建appium手机自动化测试开发环境

    手机自动化测试:搭建appium手机自动化测试开发环境   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大 ...

随机推荐

  1. 错误“AxImp.exe”已退出,代码为 -1163019603

    最近调试项目时突然出现错误"AxImp.exe"已退出,代码为 -1163019603 发现引用中的组件出现了一个感叹号 经过核对是锐浪报表的组件出现了问题,尝试打开报表设计器也无 ...

  2. 关于deepin-wine或wine更换字体方法

    前言 首先要知道,deepin-wine打包的QQ和你自己用 deepin-wine跑的windows软件,他们所在不是同一个容器 deepin打包QQ所在的容器,在你的 ~/.deepinwine ...

  3. PHP8.1.10手动安装教程及报错解决梳理

    安装教程参考一:https://www.cnblogs.com/haw2106/p/9839655.html 安装教程参考二:https://www.cnblogs.com/jiangfeilong/ ...

  4. 【Linux】通过Crontab和shell脚本实现定期备份和删除PG数据库表数据

    〇.参考资料 一.Crontab使用 1.查看状态 service crond status 2.新建crontab任务 crontab -e 输入字符串 * * * * * cd /home/big ...

  5. 【Impala】概念、原理、内外部shell、建库建表、分区、查询、自定义函数、存储压缩

    一.基本概念 1.介绍 对HDFS.Hbase数据的高性能.低延迟的交互式SQL查询功能 2.优缺点 优点:基于内存运算,无需写入磁盘,无需转化为MR,支持Data Locality调度(数据和计算在 ...

  6. CORS与CSRF在Spring Security中的使用

    背景 在项目使用了Spring Security之后,很多接口无法访问了,从浏览器的网络调试窗看到的是CORS的报错和403的报错 分析 我们先来看一下CORS是什么,和它很相似的CSRF是什么,在S ...

  7. MySQL函数--时间格式--流程控制if判断

    目录 一:函数 1.MySQL什么是函数? 2.通过help查看函数帮助 3.移除指定字符 4.大小写转换 5.获取左右起始指定个数字符 6.返回读音相似值(对英文效果) 二:时间格式实战案例 1.时 ...

  8. Go语言Golang DevOps运维开发实战

    Go语言Golang DevOps运维开发实战 提高运维意识.从下到上,从上到下的工作都要做好,对上运维工作的价值和含金量可以得到认可,对下我们的工作能够提高效率解放运维.运维意识是很重要,并不是你技 ...

  9. DataTables实现按分组小计

    效果图:

  10. [随笔所想] UBC学习生活经验分享

    当时受到了很多人的帮助,在网上也查到了很多经验帖子,比如如何办理签证,如何填写表格,要准备哪些材料以及生活上要带哪些物品,等等.当时就想到等我办理好这些,也一定和大家分享,为更多的人提供一些参考. 1 ...