需要进行先登录再测试其他模块时,登录的步骤最好不要放在用例中,因为在UI自动化测试用例中,最好不要产生依赖关系,因为这样出错了,代码不好维护,不像接口自动化测试用例,而且有依赖关系的话,也不好执行并发运行测试用例,所以依赖的登录操作可以放在夹具中执行
具体代码如下:
native_page.py代码修改如下:
from selenium.webdriver import ActionChains
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as when
class MobileKey:
ENTER = 66
VOLUME_UP = 24
VOLUME_DOWN = 25
BACK = 4
class NativePage:
def __init__(self, driver):
self.driver = driver
def find_el(self, locator):
"""查找元素"""
return self.driver.find_element(*locator)
def click(self, locator):
"""点击"""
wait = WebDriverWait(self.driver, timeout=5)
condition = when.element_to_be_clickable(locator)
element = wait.until(condition)
ActionChains(self.driver).click(element).perform()
def type(self, locator, words):
"""输入"""
el = self.driver.find_element(*locator)
el.send_keys(words)
def get_toast_text(self):
"""获取错误信息"""
toast = self.driver.find_element('xpath', '//android.widget.Toast')
return toast.text
def get_avatar_title(self):
"""获取登录后的头像名称"""
title = self.driver.find_element('id', 'com.lemon.lemonban:id/fragment_my_lemon_avatar_title')
return title.text
def width(self):
"""获取app的宽度"""
return self.driver.get_window_size()['width']
def height(self):
"""获取app的高度"""
return self.driver.get_window_size()['height']
def swipe_left(self):
"""从右往左滑动"""
self.driver.swipe(start_x=self.width() * 0.9, end_x=self.width() * 0.1,
start_y=self.height() * 0.5, end_y=self.height() * 0.5)
def swipe_right(self):
"""从左往右滑动"""
self.driver.swipe(start_x=self.width() * 0.1, end_x=self.width() * 0.9,
start_y=self.height() * 0.5, end_y=self.height() * 0.5)
def swipe_up(self):
"""从下往上滑动"""
self.driver.swipe(start_x=self.width() * 0.5, end_x=self.width() * 0.5,
start_y=self.height() * 0.9, end_y=self.height() * 0.1)
def swipe_down(self):
"""从上往下滑动"""
self.driver.swipe(start_x=self.width() * 0.5, end_x=self.width() * 0.5,
start_y=self.height() * 0.1, end_y=self.height() * 0.9)
def enter(self):
"""回车"""
self.driver.press_keycode(MobileKey.ENTER)
def volume_up(self):
"""音量加"""
self.driver.press_keycode(MobileKey.VOLUME_UP)
def volume_down(self):
"""音量减"""
self.driver.press_keycode(MobileKey.VOLUME_DOWN)
def back(self):
"""返回"""
self.driver.press_keycode(MobileKey.BACK)
conftest.py代码修改如下:
import pytest
from appium.webdriver import Remote
from pages.home_page import HomePage
from pages.login_page import LoginPage
from pages.tiku_page import TikuPage
from pages.user_page import UserPage
def get_driver():
""""启动app"""
caps = {"platformName": "Android",
"udid": "emulator-5554",
"appPackage": "com.lemon.lemonban",
"appActivity": ".activity.WelcomeActivity",
"chromedriverExecutableDir": "E:\driver"
}
driver = Remote(command_executor='http://127.0.0.1:4723/wd/hub',
desired_capabilities=caps)
# 设置隐性等待
driver.implicitly_wait(10)
return driver
@pytest.fixture(name='app') # 设置别名代替init_app
def init_app():
"""启动app"""
d = get_driver()
yield d
d.quit()
@pytest.fixture()
def homepage(app):
"""初始化homepage"""
return HomePage(app)
@pytest.fixture()
def userpage(app):
"""初始化userpage"""
return UserPage(app)
@pytest.fixture()
def loginpage(app):
"""初始化loginpage"""
return LoginPage(app)
@pytest.fixture()
def tikupage(app):
"""初始化tikupage"""
return TikuPage(app)
@pytest.fixture()
def login(homepage, loginpage, userpage):
homepage.enter_userpage()
userpage.click_login()
loginpage.login('18173179913', '179913')
return homepage.driver
新建tiku_page.py代码如下:
from pages.menu import Menu
class TikuPage(Menu):
# 题库页面中‘去登录’按钮元素
locator_login = ('id', 'com.lemon.lemonban:id/button_go_login')
# Linux题
locator_linux = ('xpath', '//*[@text="Linux"]')
# 初级
locator_chuji = ('xpath', '//*[@text="初级"]')
# 第一套题
locator_shijuan = ('xpath', '//*[@text="Linux--初级--第1套"]')
# 获取题目的序号元素
locator_title = ('id', 'com.lemon.lemonban:id/toolbar_textview')
# 点击显示答案按钮
locator_show_answer = ('id', 'com.lemon.lemonban:id/switch_button')
# 获取答案
locator_answer = ('id', 'com.lemon.lemonban:id/tvBody')
def get_msg_nologin(self):
"""未登录时的提示信息"""
el = self.driver.find_element(*self.locator_login)
return el.text
def choose_tiku(self, name):
"""通过题库名称选择题库"""
locator = ('xpath', f'//*[@text="{name}"]')
self.click(locator)
def choose_difficulty(self, level):
"""选择题库难度等级"""
locator = ('xpath', f'//*[@text="{level}"]')
self.click(locator)
def choose_shijuan(self):
"""选择试卷"""
self.click(self.locator_shijuan)
def get_item(self):
"""获取某个试卷"""
self.choose_tiku('Linux')
self.choose_difficulty('初级')
self.choose_shijuan()
def get_index(self):
"""获取题目的序号(1/15)"""
el = self.find_el(self.locator_title)
return el.text.split('/')[0]
def show_answer(self):
"""获取题目答案"""
self.click(self.locator_show_answer)
el = self.find_el(self.locator_answer)
return el.text
新建test_tiku.py代码如下:
from pages.home_page import HomePage
from pages.user_page import UserPage
from pages.tiku_page import TikuPage
class TestTiku:
def test_tiku_nologin(self, homepage: HomePage, tikupage: TikuPage):
"""没有登录的题库"""
homepage.enter_tiku()
assert tikupage.get_msg_nologin() == '去登录'
def test_tiku_login(self, login):
"""登录后的题库
1.先登录
2.选择题库 choose_tiku(name) text文本=Linux
3.选择题库难度 文本:初级
4.选择试卷:文本:Linux--初级--第1套
5.断言试卷题号:1 id=com.lemon.lemonban:id/toolbar_textview
6.点击显示答案:id= com.lemon.lemonban:id/switch_button
7.断言是否有答案:id=com.lemon.lemonban:id/tvBody 长度>0
8.滑动5次之后
9.断言试卷题号:6 id=com.lemon.lemonban:id/toolbar_textview
"""
# 登录后,点击跳转到题库页面
UserPage(login).enter_tiku()
# 初始化tikupage
tikupage = TikuPage(login)
# 得到试卷
tikupage.get_item()
# 断言题目序号
assert tikupage.get_index() == '1'
# 断言题目答案结果
assert tikupage.show_answer() != ''
# 滑动页面5次
for i in range(5):
tikupage.swipe_left()
# 断言题目答案结果
assert tikupage.get_index() == '6'
总结:
- 夹具中封装login时,一定要记得返回return homepage.driver
- TikuPage类中通过文本定位元素有两种方法:第一种就是locator写死, locator_linux = ('xpath', '//*[@text="Linux"]'),第二种:函数设置参数,调用时传入参数,这种优点是灵活,两种先一即可,我这里方法总结,两种混合在一块写了
- find_element()方法如果在NativePage类中未封装,那么在TikuPage类中使用就得用self.driver.find_element(),如果是进行了封装,就可以直接使用self.find_el()