回答

收藏

Web自动化之几个重要功能的实践

IT学院 IT学院 123 人阅读 | 0 人回复 | 2021-05-12



出品|51Testing软件测试网

本文主要内容包括以下几个功能的实现:

    文章发布

    删除单条文章用例

    删除所有文章用例

    添加ID标签实现元素定位

    登录功能验证码识别




添加文章

添加文章页面:



实现思路:

用例设计:包括添加成功和添加失败两条case。

1.元素定位

2.写标题->内容->点击发布

3.验证:toast弹窗文本内容正确

脚本实现:
from selenium.webdriver import ActionChains from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from time import sleep from basic.admin_login import Test_admin_login classTestArticle(object):def__init__(self, login):        self.login = login # 测试添加文章 deftest_add_ok(self):        title = '我的文章'        content = '我的文章内容'        expected = '文章保存成功。'#定位左侧文章列表 #文章         self.login.driver.find_element_by_xpath('//*[@id="sidebar-menu"]/li[4]/a/span[1]').click()         sleep(1) #文章管理         self.login.driver.find_element_by_xpath('//*[@id="sidebar-menu"]/li[4]/ul/li[1]/a').click()         sleep(1) #新建         self.login.driver.find_element_by_xpath('/html/body/div/div/section[3]/div/div/div/div[1]/div/div/a').click()         sleep(1) #定位文章区域 #标题         self.login.driver.find_element_by_id('article-title').send_keys(title)         sleep(1) #进入iframe         frame1=self.login.driver.find_element_by_xpath('//*[@id="cke_1_contents"]/iframe')         self.login.driver.switch_to.frame(frame1)         sleep(1) #文章内容         self.login.driver.find_element_by_xpath('/html/body').send_keys(content) #退出frame         self.login.driver.switch_to.default_content() #发布按钮         self.login.driver.find_element_by_class_name('btn-primary').click() #toast定位         loc=(By.CLASS_NAME,"toast-message") #等待toast出现         WebDriverWait(self.login.driver,5).until(EC.visibility_of_element_located(loc)) #toast文本         message=self.login.driver.find_element(*loc).text #断言判断toast文本和期望值相等 assert message==expected
(左右滑动查看完整代码)

注意点:

1.frame弹窗的切入切出

2.文章内容定位页面检查时到/html,需要自己手动添加到body下'/html/body'

3.发送失败toast弹窗消失很快,可以多次点击几下定位



删除单条文章用例

删除文章页面:



实现思路:

用例设计:删除成功。

1.鼠标悬停在文章标题

2.点击垃圾箱

3.验证:验证删除后文章数=删除前文章数-1

脚本实现:
article.py# 测试删除单篇文章deftest_delete_one_article_ok(self):# 文章管理self.login.driver.find_element_by_xpath('//*[@id="sidebar-menu"]/li[4]/ul/li[1]/a').click()        sleep(1)#删除前文章数        beforenumber=len(self.login.driver.find_elements_by_class_name('jp-actiontr'))#鼠标悬停文章内容        a=self.login.driver.find_element_by_xpath('/html/body/div/div/section[3]/div/div/div/div[2]/table/tbody/tr[2]/td[2]/strong/a')        ActionChains(self.login.driver).move_to_element(a).perform()#删除self.login.driver.find_element_by_xpath('/html/body/div/div/section[3]/div/div/div/div[2]/table/tbody/tr[2]/td[2]/div/div/a[3]').click()        sleep(1)#删除后文章数        afternumber=len(self.login.driver.find_elements_by_class_name('jp-actiontr'))#验证删除后文章数=删除前文章数-1        assert beforenumber==afternumber+1
(左右滑动查看完整代码)

技术难点:

1.鼠标悬停操作:
ActionChains(self.login.driver).movetoelement(a).perform()
(左右滑动查看完整代码)

2.文章数目使用len()函数确认

3.所有文章数目确认通过self.login.driver.findelementsbyclassname定位一组elements确认



删除所有文章用例

删除所有文章页面:



实现思路:

用例设计:删除成功。

1.点击全选复选框

2.点击批量删除

3.验证:验证文章数目=0

实现脚本:
# 测试删除所有文章deftest_delete_all_article_ok(self):#文章管理self.login.driver.find_element_by_xpath('//*[@id="sidebar-menu"]/li[4]/ul/li[1]/a').click()#点击全部复选框self.login.driver.find_element_by_xpath('/html/body/div/div/section[3]/div/div/div/div[2]/table/tbody/tr[1]/th[1]/input').click()        sleep(1)self.login.driver.find_element_by_id('batchDel').click()        sleep(1)        WebDriverWait(self.login.driver,5).until(EC.alert_is_present())        alert = self.login.driver.switch_to.alert        alert.accept()        sleep(1)#文章数目=0        afternumber = len(self.login.driver.find_elements_by_class_name('jp-actiontr'))        sleep(1)        assert afternumber==0if __name__ == '__main__':    login = Test_admin_login()    login.login_success()    testArticle = TestArticle(login)    testArticle.test_add_ok()#testArticle.test_delete_one_article_ok()    testArticle.test_delete_all_article_ok()
(左右滑动查看完整代码)

总结:

通过上面我们可以发现,自动化用例的实现及用例和功能测试用例基本上是一样的,相同的操作步骤,相同的验证方法。只不过是通过脚本的方式展现出来,通过下面的表格再次加深一下印象。





添加ID标签实现元素定位

问题情境:

在本地环境util工具类里有一个封装好的图片验证码类,实现识别图片中的验证码,需要传入参数id。

但前端页面没有id属性,需要添加一个id属性,如下图:



那么,怎么样才能向前端页面添加属性值呢?这里我们使用JS语法。

添加id的思路如下:

首先,通过上图的img标签找到要处理的HTML元素;

然后,操作这个元素,通过setAttribute添加属性及属性值;

注意:js脚本需要放到一个变量中,然后通过self.driver.execute_script(js)执行脚本。

实现脚本:
js="document.getElementsByTagName('img')[0].setAttribute('id','captchaimg')"self.driver.execute_script(js)
(左右滑动查看完整代码)

验证是否添加成功:

1.Chrome浏览器F12,找到console,输入脚本:
document.getElementsByTagName('img')[0].setAttribute('id','captchaimg')
(左右滑动查看完整代码)



2.返回element tab下,查看存在id属性如下图:



上面获取元素的方法除了标签名称还有其他方式如:

    getElementById()

    getElementByName()

    getElementByTagName()

    getElementByClassName()


至于何种方法可以根据源码查看,源码有什么用什么方法。

报错信息
javascript error: Cannot read property 'setAttribute'ofundefined
(左右滑动查看完整代码)

数组越界

源代码:
js="document.getElementsByTagName('img')[1].setAttribute('id','captchaimg')"
(左右滑动查看完整代码)

文档中一共有一个img标签,下标从0开始,所以将1改为0。

修改后:
js="document.getElementsByTagName('img')[0].setAttribute('id','captchaimg')"
(左右滑动查看完整代码)

上面提供一种处理问题的思路,当我们需要某种元素标签时,并且这种标签不存在的情况下我们可以自己利用js语法添加标签并实现调用。

同时,在遇到selenium本身语法无法解决的问题,可以借助js脚本完成,比如页面上下滑动、处理时间空间等等。



登录功能验证码识别

一般web网站登录页面都会有验证码识别功能 ,如果是公司内部测试,可以让开发人员通过屏蔽验证码或者留后门方式轻松跳过,大可不必把时间浪费在验证码识别上。

但是,大部分小伙伴一般刚开始接触自动化时都是自己找的项目,基本上述两种方法不适用。

下面推荐两种常用的验证码识别方式:

第一种OCR自动识别方式,缺点较复杂的验证码识别不出来。

第二种,第三方API使用,我这里使用的是打码平台的,除此之外百度识别或者万维易源(缺点:调用繁琐、费用较高)。

场景:识别下图的验证码。





OCR自动识别的原理

在这里我们需要使用pytesseract,它是一款用于光学字符识别(OCR)的python工具,即从图片中识别出其中嵌入的文字。

整个过程分为截取登录页面->获取验证码的位置坐标->打开截图->从截图中截取验证码的区域->使用pytesseract工具识别验证码,这里直接使用pytesseract转换介绍。

1.安装Pillow
pip install Pillow

2.安装pytesseract
pip install pytesseract

3.实现代码
from PIL import Image  导入Image函数import pytesseract  导入pytesseractdefget_file_content(filePath):# 3.验证码处理-使用OCR自动识别    qq = Image.open("D://software//project//jpress//testcases//basic//test.png")  # 打开jpg验证码图片    text = pytesseract.image_to_string(qq).strip()
(左右滑动查看完整代码)

运行查看结果返回为空,所以说这种方法对于简单的验证码还可以,复杂一点的可以直接放弃。





第三方API接口

打码平台链接地址:

http://www.ttshitu.com/docs/index.html?spm=null

首先需要注册一个账号,其次充值,1块钱够用挺长时间,找到对应的语言(如python),拷贝代码:
import base64import jsonimport requestsdef base64_api(uname, pwd,  img):withopen(img, 'rb') as f:        base64_data = base64.b64encode(f.read())        b64 = base64_data.decode()data = {"username": uname, "password": pwd, "image": b64}result = json.loads(requests.post("http://api.ttshitu.com/base64", json=data).text)ifresult['success']:returnresult["data"]["result"]else:returnresult["message"]return""if __name__ == "__main__":    img_path = "D://software//project//jpress//testcases//basic//test.png"result = base64_api(uname='你的账号', pwd='你的密码', img=img_path)    print(result)
(左右滑动查看完整代码)

将上图中的 【uname='你的账号', pwd='你的密码', img=img_path 】改成你自己的账号、密码和图片路径即可。

查看运行结果:



对比上面的识别结果,我们可以看出如果你的验证码简单推荐第一种方法,好处就是不用充钱,坏处识别度低一点;如果验证码比较复杂,推荐第二个,好处费用低、调用简单,识别率高,省时省力。

本文涉及到了真实的脚本用例设计及登录场景下借助于api接口实现验证码识别,除此之外还提供了一种解决问题的思路,有的时候没有相关元素我们可以自己添加,寻找另一种方案。

操作不重要,重要的是思路。

......
本文为51Testing软件测试网第六十一期电子杂志内容剩余精彩内容请点击下方 阅读原文查看


推荐阅读
点击阅读☞测试人,面试逃不过的灵魂三问

点击阅读☞测试中这些奇怪的问题你见过吗?

点击阅读☞新人如何做好功能测试,看这几点就够了

点击阅读☞211本科大佬的真实面试经历:测试人要不要去外包公司?

点击阅读☞2020年应聘华为测试岗三轮面试经历分享


戳“阅读原文”一起来充电吧!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
高级模式
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则