霍格沃兹测试开发学社 ceshiren.com
自动化场景:企业微信添加成员(web端)
1. 登录
2. 进入首页页面
3. 点击"添加成员"按钮
4. 填写成员信息
5. 点击"保存"按钮
6. 进入通讯录页面
7. 验证==>断言
# test_login.py 登录
"""
@Author: 霍格沃兹测试开发学社-西西
@Desc: 更多测试开发技术探讨,请访问:https://ceshiren.com/t/topic/15860
"""
import time
import yaml
from selenium import webdriver
# 企业微信的cookie 有互踢机制。
class TestCookieLogin:
def setup_class(self):
"""前置动作"""
self.driver = webdriver.Chrome()
def teardown_class(self):
"""后置处理"""
pass
# self.driver.quit()
def test_save_cookies(self):
"""获取cookie"""
# 1、访问企业微信首页
self.driver.get("https://work.weixin.qq.com/wework_admin/frame#index")
# 2、直接等待,手工扫码
time.sleep(10)
# 3、登录成功后,获取cookie
cookies = self.driver.get_cookies()
# 4、保存cookie
with open("./data/cookies.yaml", "w") as f:
yaml.safe_dump(data=cookies, stream=f)
def test_add_cookie(self):
"""植入cookie"""
# 1、访问企业微信首页 CookieDomain
self.driver.get("https://work.weixin.qq.com/wework_admin/frame#index")
# 2、获取本地 cookies
with open("./data/cookies.yaml", "r") as f:
cookies = yaml.safe_load(f)
# 3、植入cookies
for ck in cookies:
self.driver.add_cookie(ck)
# 4、访问企业微信首页
self.driver.get("https://work.weixin.qq.com/wework_admin/frame#index")
# test_contact.py 添加联系人
"""
@Author: 霍格沃兹测试开发学社-西西
@Desc: 更多测试开发技术探讨,请访问:https://ceshiren.com/t/topic/15860
"""
import yaml
from faker import Faker
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait
from utils.log_util import logger
class TestAddMemberFromHome:
def setup_class(self):
# mock 数据 姓名,account, 手机号
fake:Faker = Faker("zh_CN")
self.username = fake.name()
self.accid = fake.ssn()
self.mobile = fake.phone_number()
# 实例化
self.driver = webdriver.Chrome()
self.driver.implicitly_wait(5)
self.driver.maximize_window()
logger.info("登录")
# 1、访问企业微信首页
self.driver.get("https://work.weixin.qq.com/wework_admin/frame")
# 2、获取本地的cookie
with open("./data/cookies.yaml", "r") as f:
cookies = yaml.safe_load(f)
# 3、植入cookie
for ck in cookies:
self.driver.add_cookie(ck)
# 4、访问企业微信首页
self.driver.get("https://work.weixin.qq.com/wework_admin/frame")
def teardown_class(self):
# 不要退出
# self.driver.quit()
pass
def test_add_member(self):
# name = "aaab"
# acctid = "111112"
# phonenum = "13100000001"
# 2. 点击添加成员按钮
logger.info("点击添加成员按钮")
self.driver.find_element(By.CSS_SELECTOR, ".ww_indexImg_AddMember").click()
# 3. 填写成员信息
logger.info("填写成员信息")
# 3.1 输入用户名
self.driver.find_element(By.ID, "username").send_keys(self.username)
# 3.2 输入acctid
self.driver.find_element(By.ID, "memberAdd_acctid").send_keys(self.accid)
# 3.3 输入手机号
self.driver.find_element(By.ID, "memberAdd_phone").send_keys(self.mobile)
# 3.4 点击保存
self.driver.find_element(By.CSS_SELECTOR, ".js_btn_save").click()
# 4. 断言结果
loc_tips = (By.ID, "js_tips")
# 等到可见,再去获取结果文字
WebDriverWait(self.driver,10,2).until(expected_conditions.visibility_of_element_located(loc_tips))
tips_value = self.driver.find_element(*loc_tips).text
assert "保存成功" == tips_value
def test_delete_contact(self):
# 删除刚添加的联系人
self.driver.find_element(By.XPATH, "//*[text()='通讯录']").click()
self.driver.find_element(By.XPATH,"//span[text()='汪文']/../..//input").click()
self.driver.find_element(By.XPATH, "//*[text()='删除']").click()
self.driver.find_element(By.XPATH, "//*[@d_ck='submit_hr_helper']").click()
loc_tips = (By.ID, "js_tips")
# 等到可见,再去获取结果文字
WebDriverWait(self.driver, 10, 2).until(expected_conditions.visibility_of_element_located(loc_tips))
print(f"冒泡消息:{loc_tips}")
PO
设计思想分工
页面 ==> 类
PO
原则解读属性意义
方法意义
PO
建模PO
建模PO
与链式调用PageObject
:编写PO
类PageObject
:融入元素定位
# test_contact.py
def test_addcontact(self):
"""添加成员"""
contact_list = self.browser.login().click_add_member().\
edit_contact(self.username, self.accid,self.mobile)
tips = contact_list.get_tips()
assert tips=='保存成功'
# 删除联系人
contact_list.del_operate(self.username)
# contactlist_page.py 通讯录页面PO封装
class ContactListPage(BasePage):
_TIPS_LOC = (By.ID, "js_tips")
_INPUT_USERNAME = By.XPATH, "//span[text()='{name}']/../..//input"
_BNT_DELETE = By.XPATH, "//*[text()='删除']"
_BNT_DELLETE_SUBMIT = By.XPATH, "//*[@d_ck='submit_hr_helper']"
def get_tips(self):
"""获取提示文本"""
# 等到可见,再去获取结果文字
self.wait_element_until_visible(self._TIPS_LOC)
tips_value = self.get_text(*self._TIPS_LOC)
return tips_value
def del_operate(self, name):
# 删除刚添加的联系人
self.find_click(self._INPUT_USERNAME[0], self._INPUT_USERNAME[1].format(name=name))
self.find_click(*self._BNT_DELETE)
self.find_click(*self._BNT_DELLETE_SUBMIT)
# conftest.py
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
def pytest_runtest_makereport(item, call):
# 获取钩子方法的调用结果
out = yield
# 从钩子方法的调用结果中获取测试报告
report = out.get_result()
fail_case_info = []
# 错误类型
error_type = None
# 错误信息
error_msg = None
# 错误完整信息
error_longrepr = None
# 如果用例执行不通过
if report.outcome != "passed":
# 如果运行时有相应的错误日志则捕获日志,赋值到一个变量中
if call.excinfo:
error_type = call.excinfo.typename
error_msg = call.excinfo.value.msg
error_longrepr = str(out._result.longrepr)
case_info = {
"nodeid": report.nodeid,
"result": report.outcome,
"type": error_type,
"msg": error_msg,
"longrepr": error_longrepr
}
fail_case_info.append(case_info)
# 用例信息写入 yaml 文件
with open('../fail_record/fail_cases_info.yaml', 'a', encoding='utf-8') as f:
yaml.dump(fail_case_info, f)
logger.error(f'错误类型 =>> {error_type},\n'
f'错误信息 =>> {error_msg},\n'
f'错误详情 =>> {error_longrepr} \n')
- 知识点:web 自动化测试 L3-自动化关键数据记录
- 如果未找到元素,则
- 保存截图
- 同时保存页面源码
- 同时保存日志
- 如果找到元素,则不截图也不存 page source
# utils/except_handler.py 异常处理
def ui_exception_record(func):
def run(*args, **kwargs):
self = args[0]
try:
return func(*args, **kwargs)
except Exception as e:
# 这里添加所有的异常情况处理
# 日志
logger.warning("执行过程中发生异常")
# 截图
timestamp = int(time.time())
image_path = f"./images/"
image_file = image_path + f"image_{timestamp}.PNG"
page_source_path = f"./page_source/"
page_source_file =page_source_path + f"{timestamp}_page_source.html"
# page_source
if not os.path.exists(page_source_path):
os.makedirs(page_source_path)
with open(page_source_file, "w", encoding="u8") as f:
f.write(self.driver.page_source)
if not os.path.exists(image_path):
os.makedirs(image_path)
self.driver.save_screenshot(image_file)
allure.attach.file(image_path, name="image", attachment_type=allure.attachment_type.PNG)
# allure.attach.file(page_source_path, name="page_source", attachment_type=allure.attachment_type.HTML)
allure.attach.file(page_source_path, name="page_source", attachment_type=allure.attachment_type.TEXT)
raise e
return run
# 将装饰器装饰到 base_page.py 文件的 `do_find()` 方法上,在查找元素的时候,如果未找到,则报错,并保存截图和pagesource
# base_page.py
@ui_exception_record
def do_find(self, by, locator=None):
"""查找元素"""
logger.info(f"查找元素:by:{by}, locator:{locator}")
if locator:
return self.driver.find_element(by, locator)
else:
return self.driver.find_element(*by)