.NET项目web自动化测试实战——Selenium 2.0
🔥 交流讨论:欢迎加入我们一起学习!
🔥 资源分享:耗时200+小时精选的「软件测试」资料包
🔥 教程推荐:火遍全网的《软件测试》教程
📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
PS:这次用公司的项目来练手,希望公司不会起诉我,因为我绝对是抱着学习的态度,没有任何恶意。仅供交流学习。
该项目是基于SharePoint平台所开发的门户网站,为了切身感受一下Selenium 2.0我决定自己动手写一个自动化测试用例,而不是通过录制的方式,以加深我对一些web操作的理解。
我设计的测试用例是:检查Staff Spotlight中所包含的item对应三级页面显示的信息是否正确。具体逻辑是,在英语浏览器下检查后台list中英语Column的value和三级page中对应Column的value是否一致,在日语浏览器下检查后台list中日语Column的value和三级page中对应Column的value是否一致,如果是英语浏览器下后台list中没有勾选“English Ready”项,则在三级page中显示日语Column的value。
三级page如下:
点击页面右上角的“Edit Item”按钮可以跳转到后台list中相应的item编辑页面;点击上方的“日本语”按钮可以进行英语和日语的语言切换,点击“日本语”将切换到日本语,再点击“English”将切换到英语。
我们本次要取的页面元素就是Department,Location,Title以及Join Date的页面value。然后点击“Edit Item”按钮跳转到后台item编辑页面,按“F12”,找到对应要获取的后台元素值:
获取到对应的Column的value所在页面的元素,然后获取页面上显示的值,将其与三级page上的value按我们之前说过的逻辑进行比对,如果一样,测试通过;如果不一样,测试失败。
代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using OpenQA.Selenium; using OpenQA.Selenium.IE; using OpenQA.Selenium.Support; using OpenQA.Selenium.Support.UI; using Selenium; using mySelenium; using System.Runtime.InteropServices; using System.Threading; using System.Diagnostics; using System.Net; using System.IO; using System.Globalization;namespace mySelenium {class LoginSPSite{[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]public static extern IntPtr GetForegroundWindow();static void Main(string[] args){IWebDriver driver = new InternetExplorerDriver();IWebDriver iw = login(driver,"https://insite.ccqa11apps.com/Pages/default.aspx");INavigation navi = iw.Navigate();string language = checkLanguage(iw);if (language == "English"){//Check the English page.(检查英语页面信息。)Console.ForegroundColor = ConsoleColor.Yellow;Console.WriteLine("--English page check--");checkPageInfo(iw,"En");//Turn to the Japanese page.(转换到日语页面。)navi.GoToUrl("https://insite.ccqa11apps.com/Pages/default.aspx");waitUntilPageLoaded(iw, "ctl00_ctl21_ToggleLanguage");iw.FindElement(By.Id("ctl00_ctl21_ToggleLanguage")).Click();//Check the Japanese page.(检查日语页面信息。)Console.ForegroundColor = ConsoleColor.Yellow;Console.WriteLine("--Japanese page check--");checkPageInfo(iw,"Ja");}//Language is "Japanese".else {//Check the Japanese page.(检查日语页面信息。)Console.ForegroundColor = ConsoleColor.Yellow;Console.WriteLine("--Japanese page check--");checkPageInfo(iw,"Ja");//Turn to the English page.(转换到英语页面。)navi.GoToUrl("https://insite.ccqa11apps.com/Pages/default.aspx");waitUntilPageLoaded(iw, "ctl00_ctl21_ToggleLanguage");iw.FindElement(By.Id("ctl00_ctl21_ToggleLanguage")).Click();//Check the English page.(检查英语页面信息。)Console.ForegroundColor = ConsoleColor.Yellow;Console.WriteLine("--English page check--");checkPageInfo(iw, "En");}}//Get the 3rd page info.(从三级page中获取指定的Column的value,需要传入IWebDriver对象以及当前页面的语言种类。)private static void checkPageInfo(IWebDriver iw,string LanType){//Check 3rd page with the format: "https://insite.ccqa11apps.com/_layouts/15/InSite/pages/StaffDetails.aspx?id=" under the English environment.INavigation navi = iw.Navigate();for (int i = 1; i <= 5; i++){Console.ForegroundColor = ConsoleColor.White;Console.WriteLine("This is the " + i + " staff item check info:");navi.GoToUrl("https://insite.ccqa11apps.com/_layouts/15/InSite/pages/StaffDetails.aspx?id=" + i.ToString());var eles = iw.FindElements(By.ClassName("apps-staffdetail-content-splitline"));//Get the info from the 3rd page.(获取三级page上Column的value信息。)StaffSpotlight staffSpotlight = new StaffSpotlight();staffSpotlight.Department = eles[0].FindElement(By.ClassName("apps-staffdetail-content-splitline-bottom")).Text;staffSpotlight.Location = eles[1].FindElement(By.ClassName("apps-staffdetail-content-splitline-bottom")).Text;staffSpotlight.Title = eles[2].FindElement(By.ClassName("apps-staffdetail-content-splitline-bottom")).Text;staffSpotlight.JoinDate = eles[3].FindElement(By.ClassName("apps-staffdetail-content-splitline-bottom")).Text;//Find the "Edit Item" button.(找到“Edit Item”按钮并点击。)iw.FindElement(By.ClassName("apps-staffdetail-edit")).Click();//Wait until the element on page loaded.(等待页面元素加载完成。)waitUntilPageLoaded(iw, "Inpex_Department_$containereditableRegion");//Get the info from the backend list.(获取后台list中Column的value信息。)StaffSpotlight staffInfoFromBackend = new StaffSpotlight();staffInfoFromBackend.Department = iw.FindElement(By.Id("Inpex_Department_$containereditableRegion")).FindElement(By.ClassName("valid-text")).Text;staffInfoFromBackend.Location = iw.FindElement(By.Id("Inpex_Office_$containereditableRegion")).FindElement(By.ClassName("valid-text")).Text;//Job title is the title under English IE.(Title是日语浏览器中显示的Title,EnTitle是英语浏览器中显示的Title。)staffInfoFromBackend.Title = iw.FindElement(By.Id("Inpex_Job_Title_30756774-5931-4844-bac1-a2f463d04ca0_$TextField")).GetAttribute("value").ToString();staffInfoFromBackend.EnTitle = iw.FindElement(By.Id("Inpex_Job_Title_E_ef6d11a7-f73e-4885-bef1-527a1c03c924_$TextField")).GetAttribute("value").ToString();staffInfoFromBackend.JoinDate = iw.FindElement(By.Id("Inpex_Join_Date_b133dcfe-4e0c-4f0f-8b82-92a549516e6d_$DateTimeFieldDate")).GetAttribute("value").ToString();//Compare the actual 3rd info with the expected backend info.(将三级page中的Column value和预期value比较。)Compare("Department", staffSpotlight.Department, staffInfoFromBackend.Department);Compare("Location", staffSpotlight.Location, staffInfoFromBackend.Location);//英语页面的Title信息比对检查逻辑。if (LanType == "En"){try{ //If can get the element underneath, it means "English Ready" has been checked.(如果可以在页面上获取到该元素,说明“English Ready”这一项是勾选的。)string ifChecked = iw.FindElement(By.Id("Inpex_E_Text_a355a229-a1bb-48f5-81dd-e428a0d4fbd2_$BooleanField")).GetAttribute("checked").ToString();Console.WriteLine("The Englisht ready has been checked: " + ifChecked);//Compare the title with the backend "En" one.(比对EnTitle和三级page中的Column value是否一致。)Compare("Title", staffSpotlight.Title, staffInfoFromBackend.EnTitle);}//If can not get the element by the ID above, it means "English Ready" has not been checked.(如果获取不到“English Ready”元素下的“checked” Attribute,说明没勾选。)catch(Exception ex){WriteLog(ex);//Compare the title with the backend "Jp" one.(比对Title和三级page中的Column value是否一致。)Console.WriteLine("The Englisht ready has been checked: false");Compare("Title", staffSpotlight.Title, staffInfoFromBackend.Title);} }//日语页面的Title信息比对检查逻辑。else {staffInfoFromBackend.Title = iw.FindElement(By.Id("Inpex_Job_Title_30756774-5931-4844-bac1-a2f463d04ca0_$TextField")).GetAttribute("value").ToString();Compare("JapTitle", staffSpotlight.Title, staffInfoFromBackend.Title);}//Change the time format into the same.(统一转换三级page上的join date时间格式以及后台list item的join date时间格式,并进行比较。)string joinDateOnPage;string joinDateFromBackend;if (staffSpotlight.JoinDate != ""){DateTime dt = Convert.ToDateTime(staffSpotlight.JoinDate);joinDateOnPage = dt.ToString("yyyy-MM-dd");}else {joinDateOnPage = "";}if (staffInfoFromBackend.JoinDate != ""){DateTime dt2 = Convert.ToDateTime(staffInfoFromBackend.JoinDate);joinDateFromBackend = dt2.ToString("yyyy-MM-dd");}else {joinDateFromBackend = "";}Compare("JoinDate", joinDateOnPage, joinDateFromBackend);}}//Compare value method.(传入:对应要检查的Column的标题,三级page中Column的value,后台list中item对应Column的value。)private static void Compare(string title, string p1, string p2){if (p1 == p2){Console.ForegroundColor = ConsoleColor.Green;Console.WriteLine(title + " info on the 3rd page has passed the check.");}else {Console.ForegroundColor = ConsoleColor.Red;Console.WriteLine(title + "info on the 3rd page has not passed the check.");Console.WriteLine("The info on the 3rd page: " + p1);Console.WriteLine("The info from the backend page: " + p2);}}//Check language method.(检查当前页面所处于的语言环境,判断是英语还是日语,并返回当前语言种类。)private static string checkLanguage(IWebDriver iw){string currentLanguage;//Wait until the element on page loaded.waitUntilPageLoaded(iw, "ctl00_ctl21_ToggleLanguage");string language = iw.FindElement(By.Id("ctl00_ctl21_ToggleLanguage")).Text;if (language.Length == 3){currentLanguage = "English";return currentLanguage;}else {currentLanguage = "Japanese";return currentLanguage;}}//Wait until loaded method.(等待网页加载完毕指定元素,如果没有加载完,获取不到,捕获异常,继续等待,直到指定元素加载完毕。)private static void waitUntilPageLoaded(IWebDriver iw, string element){try{iw.FindElement(By.Id(element));}catch (Exception ex){WriteLog(ex);Thread.Sleep(2000);waitUntilPageLoaded(iw, element);}}//Login method.(登陆网站的方法,需要传入IWebDriver对象以及网站的url。)public static IWebDriver login(IWebDriver driver, string url) {INavigation navigation = driver.Navigate();navigation.GoToUrl(url);driver.FindElement(By.Id("overridelink")).Click();IntPtr myPtr = GetForegroundWindow();//IntPtr hWnd = FindWindow(null, "abc");if (myPtr != IntPtr.Zero){//Send message to the window.System.Windows.Forms.SendKeys.SendWait("dswu");System.Windows.Forms.SendKeys.SendWait("{TAB}");System.Windows.Forms.SendKeys.SendWait("1qaz2wsxE");System.Windows.Forms.SendKeys.SendWait("{ENTER}");}return driver;}//Write log method.(将捕获到的异常打印到本地log文件中。)private static void WriteLog(Exception ex){string logUrl = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\\SeleniumAutoTest.txt";if (File.Exists(@logUrl)){using (FileStream fs = new FileStream(logUrl, FileMode.Append)){using (StreamWriter sw = new StreamWriter(fs, Encoding.Default)){try{sw.Write(ex);}catch (Exception ex1){WriteLog(ex1);}finally{sw.Close();fs.Close();}}}}else{using (FileStream fs = new FileStream(logUrl, FileMode.CreateNew)){using (StreamWriter sw = new StreamWriter(fs, Encoding.Default)){try{sw.Write(ex);}catch (Exception ex1){WriteLog(ex1);}finally{sw.Close();fs.Close();}}}}}} }
这里我创建一个类,用来存储三级page以及后台list中获取到的Staff item的信息:
using System; using System.Collections.Generic; using System.Linq; using System.Text;namespace mySelenium {class StaffSpotlight{public string Department { get; set; }public string Location { get; set; }public string Title { get; set; }public string EnTitle { get; set; }public string JoinDate { get; set; }} }
按F5进行测试,结果如下:
测试通过。
覆盖多浏览器在Selenium也是很容易实现的,只需要把IE打开方法改用为指定浏览器所对应的打开方法:
IWebDriver driver = new InternetExplorerDriver();
把这句换了,之后的步骤对应做些修改即可。
自动化测试从某些方面讲确实是一劳永逸的,但是有很多时候自动化测试是完全没有必要的,尤其是项目周期很短的情况下,自动化的封装应该更偏向于具有普遍性的可复用过程,而不是业务逻辑。
有时候,产出决定付出。我们没必要为了一个两三月交付的项目写一堆自动化测试用例,否则得不偿失。自动化测试应该更偏向于长期上线、持续迭代的项目展开!否则最后失落感是一定有的。
最后我邀请你进入我们的【软件测试学习交流群:785128166】, 大家可以一起探讨交流软件测试,共同学习软件测试技术、面试等软件测试方方面面,还会有免费直播课,收获更多测试技巧,我们一起进阶Python自动化测试/测试开发,走向高薪之路
作为一个软件测试的过来人,我想尽自己最大的努力,帮助每一个伙伴都能顺利找到工作。所以我整理了下面这份资源,现在免费分享给大家,有需要的小伙伴可以关注【公众号:程序员二黑】自提!
相关文章:

.NET项目web自动化测试实战——Selenium 2.0
🔥 交流讨论:欢迎加入我们一起学习! 🔥 资源分享:耗时200小时精选的「软件测试」资料包 🔥 教程推荐:火遍全网的《软件测试》教程 📢欢迎点赞 👍 收藏 ⭐留言 …...
【Day53】代码随想录之动态规划_买卖股票ⅠⅡ
文章目录 动态规划理论基础动规五部曲:出现结果不正确: 1. 买卖股票的最佳时机2. 买卖股票的最佳时机Ⅱ 动态规划理论基础 动规五部曲: 确定dp数组 下标及dp[i] 的含义。递推公式:比如斐波那契数列 dp[i] dp[i-1] dp[i-2]。初…...

Swift Combine 使用调试器调试管道 从入门到精通二十六
Combine 系列 Swift Combine 从入门到精通一Swift Combine 发布者订阅者操作者 从入门到精通二Swift Combine 管道 从入门到精通三Swift Combine 发布者publisher的生命周期 从入门到精通四Swift Combine 操作符operations和Subjects发布者的生命周期 从入门到精通五Swift Com…...
go内置库函数实现client与server数据的发送接收
功能:客户端持续写入数据,直到输入exit退出,服务端读取数据并打印 注意:server和client目录在同一层级 服务端 server/main package mainimport ("fmt""net" )func main() {listen, err : net.Listen(&quo…...

[java基础揉碎]this
引出this: 什么是this: java虚拟机会给每个对象分配 this,代表当前对象。 这里的this就是new出来的这个对象 this的本质: this是个引用在堆中指向它自己: this的细节: 访问成员方法: 访问构造器:...

vulnhub靶场之Deathnote
一.环境搭建 1.靶场描述 Level - easy Description : dont waste too much time thinking outside the box . It is a Straight forward box . This works better with VirtualBox rather than VMware 2.靶场下载 https://www.vulnhub.com/entry/deathnote-1,739/ 3.启动环…...
Docker安装Postgresql12
1、搜索仓库中postgres docker search postgres 2、拉取镜像 docker pull postgres docker pull postgres:12 #拉取12版本的PG库 3、创建数据库文件夹 cd /temp/ && mkdir -m 755 postgres-data 注:-m表示权限,类chmod命令 4、执行命令启动…...
服务器防火墙的应用技术有哪些类型?
随着互联网的发展,网络安全问题更加严峻。服务器防火墙技术作为一种基础的网络安全技术,对于保障我们的网络安全至关重要。本文将介绍服务器防火墙的概念和作用,以及主要的服务器防火墙技术,包括数据包过滤、状态检测、代理服务、…...

IP地理位置查询定位:技术原理与实际应用
在互联网时代,IP地址是连接世界的桥梁,而了解IP地址的地理位置对于网络管理、个性化服务以及安全监控都至关重要。IP数据云将深入探讨IP地理位置查询定位的技术原理、实际应用场景以及相关的隐私保护问题,旨在为读者提供全面了解和应用该技术…...
hbuilder运行不了php文件是什么原因?
如果 HBuilder 无法运行 PHP 文件,可能是由于以下几个常见原因导致的: 未安装 PHP 解释器: HBuilder 需要安装 PHP 解释器才能运行 PHP 文件。请确保您的系统中已经安装了 PHP,并且已正确配置了环境变量。 PHP 解释器路径错误&…...
C++从入门到精通 第十六章(STL常用算法)
写在前面: 本系列专栏主要介绍C的相关知识,思路以下面的参考链接教程为主,大部分笔记也出自该教程,笔者的原创部分主要在示例代码的注释部分。除了参考下面的链接教程以外,笔者还参考了其它的一些C教材(比…...

【海贼王的数据航海:利用数据结构成为数据海洋的霸主】时间复杂度 | 空间复杂度
目录 1 -> 算法效率 1.1 -> 如何衡量一个算法的好坏? 1.2 -> 算法的复杂度 2 -> 时间复杂度 2.1 -> 时间复杂度的概念 2.2 -> 大O的渐进表示法 2.3 -> 常见时间复杂度计算 3 -> 空间复杂度 4 -> 常见复杂度对比 1 -> 算法效…...

OpenTiny Vue 组件库适配微前端可能遇到的4个问题
本文由体验技术团队 TinyVue 项目成员岑灌铭同学创作。 前言 微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略,每个应用可以选择不同的技术栈,独立开发、独立部署。 TinyVue组件库的跨技术栈能力与微前端十…...

jmeter 命令行启动 动态参数化
[Jmeter命令行参数] 一、在linux中,使用非gui的方式执行jmeter。若需更改参数,必须先编辑jmx文件,找到对应的变量进行修改,比较麻烦。因此,可以参数化一些常用的变量,直接在Jmeter命令行进行设置 二、参数…...
C++跨模块释放内存
linux一个进程只有一个堆,不要考虑这些问题,但是windows一个进程可能有多个堆,要在对应的堆上释放。 一, MT改MD 一个进程的地址空间是由一个可执行模块和多个DLL模块构成的,这些模块中,有些可能会链接到…...
jQuery浅析
jQuery 是一个快速、简洁的 JavaScript 库,旨在简化 HTML 文档遍历、事件处理、动画以及 Ajax 交互等功能。由 John Resig 在2006年创建,它极大地简化了JavaScript开发人员在处理网页文档、选择DOM元素以及执行各种效果和功能时的工作。 核心特性&#x…...
分班问题 、幼儿园分班(C语言)
题目 幼儿园两个班的小朋友排队时混在了一起,每个小朋友都知道自己跟前面一个小朋友是不是同班,请你帮忙把同班的小朋友找出来 小朋友的编号为整数,与前面一个小朋友同班用Y表示,不同班用N表示 输入 输入为空格分开的小朋友编号…...
QT 如何让多语言翻译变得简单,提高效率?
一.QT多语言如何翻译的? 在QT的多语言翻译过程中,分为两个步骤:第一步生成ts文件,第二步将ts文件翻译为qm文件。如果我们在需要多语言的情况下,qml经常使用qstr或者qwidget中使用tr等等,遍布许多个文件夹,在需要更新新的翻译时会很麻烦。整个工程收索并修改,效率十分低…...

线性代数:线性方程组解的结构
目录 齐次/非齐次方程组的解 Ax 0 的解的性质 定理 Ax b 的解的性质 相关证明 例1 例2 例3 齐次/非齐次方程组的解 Ax 0 的解的性质 定理 Ax b 的解的性质 相关证明 例1 例2 例3...
mysql之CRUD常见函数union查询
select select * from c insert 字段设置自增后,当我们指定增加一条数据后,往后增加的数据都会在该条数据后进行递增,但是可以认为的指定增加某条id不存在的数据 insert into c values(7,‘政治’) insert into c(c2) values(‘历史1’),(…...

接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...

Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序
一、开发环境准备 工具安装: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 项目初始化: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...