这是我去年刚刚接触软件测试时写的,时间有点久远,今天想整理一下,可能有些代码设计细节有所遗忘,文章大部分由去年课程汇报的ppt改编而来,见谅!
主要功能:对于126网页邮箱的登陆注册功能进行测试。

为了尽量减少代码冗余,本项目代码主要分为三层分别是 base层(基类 页面层重复的代码 公共的方法)page层(页面层 不同页面的具体操作)scripts层(业务层 对页面进行测试)
其余包中为美化项目功能或者非必需内容
由基类提供各种网页自动化方法,再有page层将方法组装成一个新的函数,完成对网页的自动化操作。

调用自身的函数来组成完整的自动化操作


为了方便我把所有的xpath元素写到了一个文件中,方便阅读,添加和调用

问题1:
注册部分当我们填写手机号时,失去焦点才会出现验证码框

解决方式1:
我第一个想法是既然是失去焦点,那么后续本来就要点击 同意服务条款 ,所以我先进行一次点击单选框的点击事件,输入验证码后再次点击单选框(由于第一次点击是失去焦点并增加验证框,所以并不会勾选,所以需要再次勾选) 事实上这样处理是在这个测试用例中可以的,但是当测试用例变为 手机号码不全或者手机号码格式有问题的时候,这一次的点击单选框事件会触发(应该是由于手机号错误而没有弹出验证框,导致这个事件顺利触发了)那么后续我再次点击时,会导致单选框不被勾选而出错。 那么我提供了两种解决方法,一种是直接失焦,一种点击事件,点击空白处,具体代码在下一页。


问题2:
登陆框是被网页内置的一个框架,我们如果直接使用xpath等查询元素的手段,很难定位
解决方式2:
我们要先进入这个iframe,再定位元素。 1.如果自带id或者name driver.switch_to.frame(‘id或者name的值’) 2.没有id或者name,利用xpath,css等 iframe=driver.find_element_by_xpath("...") driver.switch_to.frame(iframe) 3.通过索引,但是一定要记得加s,找错很难看到,错过!!! iframe1=driver.find_elements_by_tag_name("iframe")[0] driver.switch_to.frame(iframe1)

问题3:
元素定位的时候你会发现他的id,class中有很多数字是动态的,应该是时间戳之类的
解决方案3:
这个其实不难解决,但是需要大家看一下xpath的基本用法或者css。这个其实归根结底是对于元素的定位,我这个项目中其实除了登陆的几个元素(有直接的name,不需要处理)其余的全部都是由xpath定位的,我总结一下这个126邮箱需要会的xpath基础知识(浏览器直接复制的xpath大部分不行,要自己手写)。
1. // 从任意元素开始
2. / 下一层元素
3. /div[2] 这种表示在下一层中第2个div ,类推
4. @属性 某个标签的属性
5. 标签[contains(@属性,”.....”)] “.....”中表示这个属性的值中包含的内容
6. 标签[contains(text(),”.....”)] “.....”中表示这个标签的值,内容

import time
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
class Base:
# 初始化
def __init__(self):
self.driver = webdriver.Chrome()
self.driver.maximize_window()
self.driver.get("https://www.126.com/")
# self.driver.get("https://mail.163.com/register/index.htm?from=126mail&utm_source=126mail")
# 进入内置页面
# def base_find_frame(self):
# iframe1 = self.driver.find_elements_by_tag_name("iframe")[0]
# self.driver.switch_to.frame(iframe1)
#
# def base_return_page(self):
# self.driver.switch_to.default_content()
# 查找元素方法
# 底层方法 return self.find_element(by=By.CSS_SELECTOR, value=css_selector)
def base_find_element(self,loc,timeout=30,poll_frequency=105):
return WebDriverWait(self.driver,timeout=timeout,poll_frequency=poll_frequency).until(lambda x:x.find_element(*loc))
# 点击方法
# 不用解包!!!!! 泪目 找了好久的错
def base_click(self,loc):
self.base_find_element(loc).click()
# 输入方法
def base_input(self,loc,value):
el=self.base_find_element(loc)
#清空
el.clear()
#输入
el.send_keys(value)
# 获取文本方法
def base_get_text(self,loc):
return self.base_find_element(loc).text
# 截图方法
def base_get_png(self):
self.driver.get_screenshot_as_file("../img/fail in {}.png".format(time.strftime("%Y_%m_%d %H_%M_%S")))

__init__.py
from selenium.webdriver.common.by import By
# 进入登录框
login_frame = By.XPATH, '//iframe[contains(@id,"x-URS-iframe")]'
# 登录框email
login_email = By.NAME, "email"
# 登录框密码
login_password = By.NAME, "password"
# 登录按钮
login_button = By.ID, "dologin"
# 登陆报错
login_err_sign = By.XPATH, '//div[@id="nerror"]/div[2]'
# 写信按钮
write_letter = By.XPATH, '//div[@id="dvNavTop"]/ul/li[2]/span[2]'
# 邮箱地址无效,返回编辑
email_err_return = By.XPATH, '//div[@class="js-component-button nui-btn "]/span[contains(text(),"返回编辑")]'
# 输入收件人邮箱
email_path = By.XPATH, '//div[@class="js-component-emailinput nui-addr nui-editableAddr nui-editableAddr-edit"]/input[@class="nui-editableAddr-ipt"]'
# 去除收件人
del_email = By.XPATH, '//div[contains(@id,"_mail_emailblock")]/a[1]'
# 输入主题
email_title = By.XPATH, '//input[contains(@id,"subjectInput")]'
# 正文框架
email_frame = By.XPATH, '//iframe[@class="APP-editor-iframe"]'
# 输入正文
email_text = By.XPATH, '//body[@class="nui-scroll"]'
# 发送
email_p_button = By.XPATH, '//footer[contains(@class,"jp")]/div[@role="button"]/span[contains(text(),"发送")]'
# 发送成功
email_p_success = By.XPATH, '//h1[contains(@id,"succInfo")]'
# 邮箱格式不对
email_err_geshi = By.XPATH, '//div[contains(@id,"_mail_emailblock")]/@title'
# 无主题时确认
email_notitle_yes = By.XPATH, '//div[contains(@id,"_mail_button")]/span[contains(text(),"确 定")]'
# 注册输入邮箱
register_email = By.XPATH, '//div[@class="item"]/input[@class="username"]'
# 注册输入密码
register_password = By.XPATH, '//div[@class="item"]/input[@class="password"]'
# 注册输入手机
register_tel = By.XPATH, '//div[@class="item"]/input[@class="phone"]'
# 注册单选框
register_alert = By.XPATH, '//div[@class="custom-checkbox service"]/span'
# 注册按钮
register_button = By.XPATH, '//div[@class="register-option"]/a'
# 前往注册
go_register_button = By.XPATH, '//div[@class="loginWrap"]//a[1]'
# 邮箱地址不能为空
register_email_errtext = By.XPATH, '//div[@class="item error"]/div[2]'
# 邮箱密码
register_password_errtext = By.XPATH, '//div[@class="m-register-box-free"]/div[2]/div[@class="tip f-dn"]'
# 手机错误
register_tel_errtext = By.XPATH, '//div[@class="m-register-box-free"]/div[3]/div[@class="tip f-dn"]'
# 验证码错误
register_code_errtext = By.XPATH, '//div[@class="m-register-box-free"]/div[4]/div[@class="tip f-dn"]'
# 不勾选单选
register_gouxuan_errtext = By.XPATH, '//div[@class="custom-checkbox service error"]/div'
# 手机号码错误
register_telephone_errtext = By.XPATH, '//div[@class="m-register-box-free"]/div[3]/div[2]'
# 空白
white_=By.XPATH,'//div[@class="register-container"]'
page_email.py
import unittest
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
import page
from base.base import Base
from page.page_login import PageLogin
class PageEmail(Base):
# 点击写信
def email_click_write_letter(self,write_letter):
self.base_click(page.write_letter)
# 填写收件人
def email_write_emailpath(self,email_path):
self.base_input(page.email_path,email_path)
# 填写主题
def email_write_title(self,email_title):
self.base_input(page.email_title,email_title)
# 填写正文
def email_write_text(self,email_text):
self.base_input(page.email_text,email_text)
# 点击发送
def email_click_button(self,email_p_button):
self.base_click(page.email_p_button)
# 处理收件人异常信息
# 处理主题为空
def page_email_write_email(self,email_path,email_title,email_text):
self.pagelogin=PageLogin()
self.pagelogin.page_login("pengyufeng126","abc123,,")
time.sleep(1)
self.base_click(page.write_letter)
self.email_write_emailpath(email_path)
self.email_write_title(email_title)
iframe1 = self.base_find_element(page.email_frame)
self.driver.switch_to.frame(iframe1)
self.email_write_text(email_text)
self.driver.switch_to.default_content()
self.email_click_button()
time.sleep(2)
page_login.py
import time
import page
from base.base import Base
class PageLogin(Base):
# 进入内置页面
# def page_in_frame(self,login_frame):
# self.base_find_element(page.login_frame,login_frame)
# 输入账号
def page_input_email(self, login_email):
# self.base_find_frame(0)
self.base_input(page.login_email, login_email)
# 输入密码
def page_input_password(self, login_password):
self.base_input(page.login_password, login_password)
# 点击登录
def page_click_login(self, login_button):
self.base_click(page.login_button)
# 获取异常信息
def page_err_text(self):
return self.base_get_text(page.login_err_sign)
# 账号密码错误截图
def page_login_err(self):
return self.base_get_png()
'''
登陆功能
'''
def page_login(self, login_email, login_password):
time.sleep(1)
iframe1 = self.base_find_element(page.login_frame)
self.driver.switch_to.frame(iframe1)
self.page_input_email(login_email)
self.page_input_password(login_password)
self.base_click(page.login_button)
time.sleep(2)
# self.page_click_login()
# 点击写信
def email_click_write_letter(self,write_letter):
self.base_click(page.write_letter)
# 填写收件人
def email_write_emailpath(self,email_path):
self.base_input(page.email_path,email_path)
# 填写主题
def email_write_title(self,email_title):
self.base_input(page.email_title,email_title)
# 填写正文
def email_write_text(self,email_text):
self.base_input(page.email_text,email_text)
# 无主题时确认
def email_title_none(self):
self.base_click(page.email_notitle_yes)
# 点击发送
def email_click_button(self,email_p_button):
self.base_click(page.email_p_button)
# 错误截图
def email_err_write(self):
return self.base_get_png()
# 获取邮箱格式错误
def email_err_geshi(self):
return self.base_find_element(page.email_err_geshi).text()
'''
写邮件功能
'''
def page_email_write_email(self, email_path, email_title, email_text):
self.page_login("pengyufeng126", "abc123,,")
time.sleep(1)
self.base_click(page.write_letter)
time.sleep(1)
self.email_write_emailpath(email_path)
self.email_write_title(email_title)
iframe1 = self.base_find_element(page.email_frame)
self.driver.switch_to.frame(iframe1)
time.sleep(1)
self.email_write_text(email_text)
self.driver.switch_to.default_content()
time.sleep(1)
self.base_click(page.email_p_button)
time.sleep(1)
if '确定真的不需要写主题吗?' in self.driver.page_source:
self.base_click(page.email_notitle_yes)
self.base_click(page.email_p_button)
time.sleep(1)
page_register.py
import time
import page
from base.base import Base
class PageRegister(Base):
# 点击注册
def page_go_register(self,go_register_button):
self.base_click(page.go_register_button)
# 输入邮箱地址
def page_register_email(self,register_email):
self.base_input(page.register_email,register_email)
# 输入密码
def page_register_password(self,register_password):
self.base_input(page.register_password, register_password)
# 输入手机号
def page_register_tel(self,register_tel):
self.base_input(page.register_tel, register_tel)
# 勾选服务条款
def page_register_select(self,register_alert):
self.base_click(page.register_alert)
# 点击注册
def page_register_button(self,register_button):
self.base_click(page.register_button)
# 返回错误提示
def page_register_err1_text(self):
return self.base_get_text(page.register_email_errtext)
def page_register_err2_text(self):
return self.base_get_text(page.register_password_errtext)
def page_register_err3_text(self):
return self.base_get_text(page.register_code_errtext)
def page_register_err4_text(self):
return self.base_get_text(page.register_telephone_errtext)
# 错误截图
def page_register_get_err(self):
return self.base_get_png()
'''
注册功能
'''
def page_register(self,register_email,register_password,register_tel):
# time.sleep(1)
# iframe1 = self.base_find_element(page.login_frame)
# self.driver.switch_to.frame(iframe1)
# self.base_click(page.go_register_button)
self.page_register_email(register_email)
self.page_register_password(register_password)
self.page_register_tel(register_tel)
# self.base_click(page.register_alert)
self.base_click(page.white_)
time.sleep(1)
self.base_click(page.register_alert)
self.base_click(page.register_button)
time.sleep(1)

test_email_write.py
import unittest
from parameterized import parameterized
from page.page_login import PageLogin
def get_data():
return [
("xxxxxx@qq.com","测试","测试邮件","邮件发送成功"),
("","测试","测试邮件","请填写收件人地址后再发送"),
("xxxxxx","测试","测试邮件","该地址格式有误,请双击修改"),
("xxxxxx@qq.com","测试","","")
# ("xxxxxx@qq.com","","测试邮件","邮件发送成功"),
# ("xxxxxx@qq.com","","","邮件发送成功")
]
#xxxxxx为你的邮箱账号
class TestWriteEmail(unittest.TestCase):
# setUp
def setUp(self):
# 实例化对象
self.writeemail=PageLogin()
# tearDown
def tearDown(self):
self.writeemail.driver.quit()
# 登陆测试方法
@parameterized.expand(get_data())
def test_login_write01(self,email_path,email_title,email_text,right_result):
self.writeemail.page_email_write_email(email_path,email_title,email_text)
try:
self.assertIn(right_result, self.writeemail.driver.page_source)
except AssertionError:
self.writeemail.email_err_write()
test_login.py
import unittest
from page.page_login import PageLogin
from parameterized import parameterized
def get_data():
return [("xxxxxx","","请输入密码"),
("","abc123,,","请输入账号"),
("xxxxxxx", "abc123,,", "账号或密码错误"),
("xxxxxx","abc123,,",""),
("@@aa","abc123,,","帐号格式错误")]
class TestLogin(unittest.TestCase):
# setUp
def setUp(self):
# 实例化对象
self.login=PageLogin()
# self.driver = webdriver.Chrome()
# self.driver.maximize_window()
# self.driver.get("https://www.126.com/")
# tearDown
def tearDown(self):
self.login.page_login_err()
self.login.driver.quit()
# 登陆测试方法
@parameterized.expand(get_data())
def test_login01(self,email,password,right_result):
self.login.page_login(email,password)
# msg=self.login.page_err_text()
# # print(msg)
# try:
# self.assertEqual(msg,right_result)
# except AssertionError:
# self.login.page_login_err()
try:
# assert right_result in self.login.driver.page_source
self.assertIn(right_result,self.login.driver.page_source,"111")
except AssertionError:
self.login.page_login_err()
text_register.py
import unittest
from parameterized import parameterized
from page.page_register import PageRegister
def get_data1():
return [("", "abc123,,", "19xxxxxxxx", "邮箱地址不能为空"),
("12344", "abc123,,", "191xxxxx", "长度应为6~18个字符"),
("12344@", "abc123,,", "191xxxxxx", "只能输入字母、数字、下划线"),
("12345678@", "abc123,,", "191216xxxxx", "只能输入字母、数字、下划线")]
def get_data2():
return [("xxxxxxxx", "", "1912xxxxxxx", "密码不能为空"),
("xxxxxxx", "1", "1912xxxxxxx", "密码长度应为8-16个字符"),
("xxxxxxxxxx", "a1234567", "191xxxxxx", '密码需包含“大小写字母、数字、标点符号”中3种以上的组合')]
def get_data3():
return [("xxxx1xxxx", "abc123,,", "1xxxxxxx", "验证码不能为空")]
def get_data4():
return [("xxxxxxx", "abc123,,", "19xxxxx", "请填写正确的中国大陆地区手机号,其他地区手机号请点击此处")]
def get_data5():
return [("xxxxxxx", "abc123,,", "19xxxxx","注册成功")]
#上方数据需要自己改动
class TestRegister(unittest.TestCase):
# setUp
def setUp(self):
# 实例化对象
self.register = PageRegister()
# tearDown
def tearDown(self):
self.register.driver.quit()
# 注册测试方法 没有账号
@parameterized.expand(get_data1())
def test_register01(self, email, password, tel, right_result):
self.register.page_register(email, password, tel)
result = self.register.page_register_err1_text()
self.assertEqual(right_result, result)
self.register.page_register_get_err()
# 注册测试方法,没有密码
@parameterized.expand(get_data2())
def test_register02(self, email, password, tel, right_result):
self.register.page_register(email, password, tel)
result = self.register.page_register_err2_text()
self.assertEqual(right_result, result)
self.register.page_register_get_err()
# 注册测试方法 没有验证码
@parameterized.expand(get_data3())
def test_register03(self, email, password, tel, right_result):
self.register.page_register(email, password, tel)
result = self.register.page_register_err3_text()
self.assertEqual(right_result, result)
self.register.page_register_get_err()
# 注册测试方法 手机号不完整
@parameterized.expand(get_data4())
def test_register04(self, email, password, tel, right_result):
self.register.page_register(email, password, tel)
result = self.register.page_register_err4_text()
self.assertEqual(right_result, result)
# self.assertIn(right_result, self.register.driver.page_source)
self.register.page_register_get_err()
# @parameterized.expand(get_data5())
# def test_register03(self, email, password, tel, right_result):
# self.register.page_register(email, password, tel)
# self.assertIn(right_result, self.register.driver.page_source, "111")

run_htmlrunner.py
import time
import unittest
from lib.HTMLTestRunner import HTMLTestRunner
suite = unittest.defaultTestLoader.discover("../scripts", pattern="text_register.py")
# suite = unittest.defaultTestLoader.discover("../scripts", pattern="text_email_write.py")
report_dir = "report in {}.html".format(time.strftime("%Y_%m_%d %H_%M_%S"))
with open(report_dir, "wb") as f:
HTMLTestRunner(stream=f, verbosity=2, title="自动化测试报告", description="操作系统 win11").run(suite)

本项目测试报告利用HTMLTestRunner形成测试报告
‘’‘ 定义测试套件 原方法需要实例化unittestTextRunner() 这里在下面实例化HTMLTextRunner() pattern后写test文件’‘’
suite = unittest.defaultTestLoader.discover("../scripts", pattern="text_register.py")
‘’‘ 定义生成文件位置 若使用unittest 自带报告TextTestRunner需要自己建文件夹!!!用时间函数命名 ’‘’
report_dir = "report in {}.html".format(time.strftime("%Y_%m_%d %H_%M_%S")) ‘’‘HTMLTestRunner是经过原生TextTestRunner代码中加入HTML格式的插件 打开文件并写入数据 在html中必须使用wb!!!必填参数只有stream!!!’‘’
with open(report_dir, "wb") as f: HTMLTestRunner(stream=f, verbosity=2, title="自动化测试报告", description="操作系统 win11").run(suite)
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。
我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere
Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/
我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test
我已经构建了一些serverspec代码来在多个主机上运行一组测试。问题是当任何测试失败时,测试会在当前主机停止。即使测试失败,我也希望它继续在所有主机上运行。Rakefile:namespace:specdotask:all=>hosts.map{|h|'spec:'+h.split('.')[0]}hosts.eachdo|host|begindesc"Runserverspecto#{host}"RSpec::Core::RakeTask.new(host)do|t|ENV['TARGET_HOST']=hostt.pattern="spec/cfengine3/*_spec.r
我在app/helpers/sessions_helper.rb中有一个帮助程序文件,其中包含一个方法my_preference,它返回当前登录用户的首选项。我想在集成测试中访问该方法。例如,这样我就可以在测试中使用getuser_path(my_preference)。在其他帖子中,我读到这可以通过在测试文件中包含requiresessions_helper来实现,但我仍然收到错误NameError:undefinedlocalvariableormethod'my_preference'.我做错了什么?require'test_helper'require'sessions_hel
只是想确保我理解了事情。据我目前收集到的信息,Cucumber只是一个“包装器”,或者是一种通过将事物分类为功能和步骤来组织测试的好方法,其中实际的单元测试处于步骤阶段。它允许您根据事物的工作方式组织您的测试。对吗? 最佳答案 有点。它是一种组织测试的方式,但不仅如此。它的行为就像最初的Rails集成测试一样,但更易于使用。这里最大的好处是您的session在整个Scenario中保持透明。关于Cucumber的另一件事是您(应该)从使用您的代码的浏览器或客户端的角度进行测试。如果您愿意,您可以使用步骤来构建对象和设置状态,但通常您
我有:When/^(?:|I)follow"([^"]*)"(?:within"([^"]*)")?$/do|link,selector|with_scope(selector)doclick_link(link)endend我打电话的地方:Background:GivenIamanexistingadminuserWhenIfollow"CLIENTS"我的HTML是这样的:CLIENTS我一直收到这个错误:.F-.F--U-----U(::)failedsteps(::)nolinkwithtitle,idortext'CLIENTS'found(Capybara::Element