自动化测试如此容易!多语言自动化测试框架 Selenium 编程(C#篇)
介绍
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
更改为 eager
或 none
以加快会话加载速度。
设置方法:
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=file
的 input
标签中,填写本地路径的文件地址,这个地址需要填写文件的绝对路径。
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#篇)的更多相关文章
- Android 框架式编程 —— 起篇
一般的,在开发的时候,写过的代码在需求变更后,发现需要改动非常多的地方,那么说明之前的代码的架构肯定是存在问题的. 下面我们结合面向对象的六大基本原则谈Android 框架式编程.首先先介绍一下面向对 ...
- RobotFramework自动化测试框架-Selenium Web自动化(二)关于在RobotFramework中如何使用Selenium很全的总结(上)
好久没有继续分享关于自动化测试相关的东西了,自动化在现今的测试领域已经越来越重要了,大部分公司在测试岗位招聘中都需要会相关的自动化测试知识.而 RobotFramework自动化测试框架 是自动化测试 ...
- RobotFramework自动化测试框架-Selenium Web自动化(三)关于在RobotFramework中如何使用Selenium很全的总结(下)
本文紧接着RobotFramework自动化测试框架-Selenium Web自动化(二)关于在RobotFramework中如何使用Selenium很全的总结(上)继续分享RobotFramewor ...
- 《Selenium 2自动化测试实战 基于Python语言》中发送最新邮件无内容问题的解决方法
虫师的<Selenium 2自动化测试实战 基于Python语言>是我自动化测试的启蒙书 也是我推荐的自动化测试入门必备书,但是书中有一处明显的错误,会误导很多读者,这处错误就是第8章自动 ...
- 小白学 Python 爬虫(28):自动化测试框架 Selenium 从入门到放弃(下)
人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...
- 《Selenium2自动化测试实战--基于Python语言》 --即将面市
发展历程: <selenium_webdriver(python)第一版> 将本博客中的这个系列整理为pdf文档,免费. <selenium_webdriver(python)第 ...
- 关于《Selenium3自动化测试实战--基于python语言》
2016年1月,机缘巧合下我出版了<Selenium2自动化测试实战--基于python语言>这本书,当时写书的原因是,大部分讲Selenium的书并不讲编程语言和单元测试框,如果想在项目 ...
- selenium2自动化测试实战--基于Python语言
自动化测试基础 一. 软件测试分类 1.1 根据项目流程阶段划分软件测试 1.1.1 单元测试 单元测试(或模块测试)是对程序中的单个子程序或具有独立功能的代码段进行测试的过程. 1.1.2 集成测试 ...
- 移动端自动化测试(一)之 Appium+Pyhton环境准备篇
移动端自动化测试(一)之 Appium+Pyhton环境准备篇 2016-11-17 16:51 by CockRoacher, 5046 阅读, 1 评论, 收藏, 编辑 由于工作的需要进行Andr ...
- 手机自动化测试:搭建appium手机自动化测试开发环境
手机自动化测试:搭建appium手机自动化测试开发环境 poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大 ...
随机推荐
- qtcreator修改界面但是没有更新
原因 我之前修改了项目名(简单的修改文件夹和.pro文件名),但是项目构建的位置还是之前目录. 解决 将 build directory改为新的目录即可.
- psutil.AccessDenied: psutil.AccessDenied
解决办法 import psutil for proc in psutil.process_iter(): try: print(proc.name()) except (psutil.NoSuchP ...
- 【大数据面试】【框架】kafka:组成、台数/参数配置、持久化、ISR队列、宕机、丢数据、重复数据、数据积压、优化各种配置(刷盘、存盘、副本、压缩)、zk、其他
一.基本信息 1.组成 生产者 broker 消费者 zookeeper:brokerid.consumer信息(不包含生产者的信息) 2.需要安装多少台 2 * (生产者的峰值生产速率 * 副本 / ...
- selenium常用配置
def init_chrome_options(self,): chrome_options = webdriver.ChromeOptions() # 设置浏览器初始 位置x,y & 宽高x ...
- CTFshow——funnyrsa3
题目如下: 题目分析: 发现常规rsa不存在的dp.查找资料知道 dp ≡ d mod (p - 1).意识到dp是解题关键,可能dp和n存在某种关系可以解出p或者去,跟之前有一题有点类似,求p和q之 ...
- RestTemplate获取json数组
1.需求描述 接口返回的是一个json数组,要获取到接口返回值并用实体类list接住. 2.解决方法 使用springboot框间自带的Http的工具类RestTemplate调接口,其返回值用hut ...
- c语言基础理解(原创)
家中小女初上大学开学计算机课程,学习C语言时遇到困难,为帮助她尽快入门,特写了这篇基本概念理解,希望帮她快速认识清楚C语言的本质.发到博客园上,也帮助同样的C语言初学者轻松掌握C语言的本质 ...
- [编程基础] C++多线程入门1-创建线程的三种不同方式
原始C++标准仅支持单线程编程.新的C++标准(称为C++11或C++0x)于2011年发布.在C++11中,引入了新的线程库.因此运行本文程序需要C++至少符合C++11标准. 1 创建线程的三种不 ...
- 从开发属于你自己的第一个 Python 库,做一名真正的程序员「双语版」
你好,我是悦创.之前我在 CSDN 编写了一篇开发 Python 库的教程,有人加我提问到的一些问题,我来更新一下这篇文章:https://blog.csdn.net/qq_33254766/arti ...
- Java运算的精度和溢出问题
double和float的0.1问题 代码如下 public class demo2 { public static void main(String[] args) { float f=0.1f; ...