雪球APP:
实现股票查询:(Search)
股票选择:(Selected)
登陆操作的封装:
Profilepage页面
登陆页面
目录结构:
AndroidClient.py主要实现app的安装的启动功能:
from appium import webdriver
from appium.webdriver.webdriver import WebDriver
class AndroidClient(object):
driver:WebDriver
@classmethod
def installApp(cls)->WebDriver:
caps = {}
# caps['app']='app存放的位置' #安装app
caps["platformName"] = "android"
caps["deviceName"] = "hogwarts"
caps["appPackage"] = "com.xueqiu.android"
caps["appActivity"] = ".view.WelcomeActivityAlias"
caps["autoGrantPermissions"] = "true" # 自动授权
# caps["noReset"] = True
cls.driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
cls.driver.implicitly_wait(20) # 隐式等待
return cls.driver
@classmethod
def restartApp(cls)->WebDriver:
caps = {}
caps["platformName"] = "android"
caps["deviceName"] = "hogwarts"
caps["appPackage"] = "com.xueqiu.android"
caps["appActivity"] = ".view.WelcomeActivityAlias"
# caps["autoGrantPermissions"] = "true" # 启动的时候将,noReset设置成True就不需要这一句代码自动授权
caps["noReset"] = True
caps["unicodeKeyboard"]=True
caps["resetKeyboard"]=True
cls.driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
cls.driver.implicitly_wait(20) # 隐式等待
return cls.driver
app.py
from page_object.page.BasePage import BasePage
from page_object.page.MainPage import MainPage
class App(BasePage):
@classmethod
def main(cls):
cls.getClient().restartApp()
return MainPage()
BasePage.py,所有page页都继承这个页面
from page_object.driver.AndroidClient import AndroidClient
from appium.webdriver.webelement import WebElement
from selenium.webdriver.common.by import By
class BasePage(object):
def __init__(self):
self.driver=self.getDriver()
@classmethod
def getDriver(cls):
cls.driver=AndroidClient.driver
return cls.driver #没想通
@classmethod
def getClient(cls):
return AndroidClient # 没想通
def find(self,kv)->WebElement:
#todo:处理弹框
return self.driver.find_element(*kv)
def findByText(self,text)->WebElement:
return self.find((By.XPATH,"//*[@text='%s']" %text))
LoginPage.py
from selenium.webdriver.common.by import By
from page_object.page.BasePage import BasePage
class LoginPage(BasePage):
_back_locator=(By.ID,"iv_action_back")
_phone_login=(By.ID,"iv_login_phone")
_wx_login=(By.ID,"iv_login_wx")
_weibo_login=(By.ID,"iv_login_weibo")
_qq_login=(By.ID,"iv_login_qq")
_other_login=(By.ID,"login_more")
_register_phone_number=(By.ID,"register_phone_number")
_register_code=(By.ID,"register_code")
_button_next=(By.ID,"button_next")
_tv_login_with_account=(By.ID,"tv_login_with_account")
_login_account=(By.ID,"login_account")
_login_password=(By.ID,"login_password")
_error_msg=(By.ID,"md_content")
#_error_sue=()
def loginByWX(self):
return self
def loginByMSG(self,phone,code):
return self
def loginByPassword(self, account, password):
self.find(self._tv_login_with_account).click()
self.find(self._login_account).send_keys(account)
self.find(self._login_password).send_keys(password)
self.find(self._button_next).click()
def loginSuccessByPassword(self,account,password):
from page_object.page.MainPage import MainPage #为什么会这样?
return MainPage()
def back(self):
self.find(self._back_locator).click()
from page_object.page.ProfilePage import ProfilePage #为什么会这样?
return ProfilePage()
def getErrorMsg(self):
msg= self.find(self._error_msg).text
self.findByText("确定").click()
return msg
MainPage.py
from selenium.webdriver.common.by import By
from page_object.page.BasePage import BasePage
from page_object.page.ProfilePage import ProfilePage
from page_object.page.SelectedPage import SelectedPage
from page_object.page.SearchPage import SearchPage
class MainPage(BasePage):
_profile_button=(By.ID,"user_profile_icon")
_search_button=(By.ID,"tv_search")
def gotoSelected(self):
zixuan = (By.XPATH, "//*[@text='自选']")
self.find(zixuan) # self.driver.find_element(By.XPATH,"//*[@text='自选']")
self.find(zixuan).click()
return SelectedPage()
def gotoSearch(self):
self.find(self._search_button).click()
return SearchPage()
def gotoProfile(self):
self.find(MainPage._profile_button).click()
return ProfilePage()
ProfilePage.py
from selenium.webdriver.common.by import By
from page_object.page.BasePage import BasePage
from page_object.page.LoginPage import LoginPage
class ProfilePage(BasePage):
_phone_login = (By.ID, "iv_login_phone")
def gotoLogin(self):
self.find(self._phone_login).click()
return LoginPage()
SearchPage.py
from selenium.webdriver.common.by import By
from page_object.page.BasePage import BasePage
import time
class SearchPage(BasePage):
_edit_locator=(By.CLASS_NAME,"android.widget.EditText")
_searched_lab=(By.XPATH,"//*[contains(@resource-id,'name') and @text='招商银行']")
def search(self, name):
self.find(self._edit_locator).send_keys(name)
self.find(self._searched_lab).click()
time.sleep(2)
return self #为了进行链式调用,一直用.调用
def addToSelected(self,text):
follow_button = (By.XPATH, "//*[contains(@resource-id,'stockCode') and contains(@text,'%s')]"
% text + "/../../..//*[contains(@resource-id,'follow_btn')]")
self.find(follow_button).click()
return self
def removeFromSelected(self,text):
follow_button = (By.XPATH, "//*[contains(@resource-id,'stockCode') and contains(@text,'%s')]"
% text + "/../../..//*[contains(@resource-id,'followed_btn')]")
self.find(follow_button).click()
return self
def isInSelected(self,text):
folled_button=(By.XPATH,"//*[contains(@resource-id,'stockCode') and contains(@text,'%s')]"
%text+"/../../..//*[contains(@resource-id,'follow')]")
id=self.find(folled_button).get_attribute("resourceId")
print(id)
return "followed_btn" in id
def cancel(self):
self.findByText("取消").click()
def searchByUser(self,key):
pass
def isFollowed(self):
pass
SelectedPage.py
from selenium.webdriver.common.by import By
from appium.webdriver.common.mobileby import MobileBy #是对By的补充,只能使用在app中
from page_object.page.BasePage import BasePage
class SelectedPage(BasePage):
def addDefault(self):
return self
def gotoHS(self):
self.findByText("沪深").click()
return self
def getPriceByName(self,name):
priceLocator=(By.XPATH,"//*[contains(@resource-id,'portfolio_stockName') and @text='%s']" %name+
"/../../../..//*[contains(@resource-id,'item_layout')]")
price=self.find(priceLocator).text
return float(price)
test_login.py:
from selenium.webdriver.common.by import By
from appium.webdriver.common.mobileby import MobileBy #是对By的补充,只能使用在app中
from page_object.page.BasePage import BasePage
class SelectedPage(BasePage):
def addDefault(self):
return self
def gotoHS(self):
self.findByText("沪深").click()
return self
def getPriceByName(self,name):
priceLocator=(By.XPATH,"//*[contains(@resource-id,'portfolio_stockName') and @text='%s']" %name+
"/../../../..//*[contains(@resource-id,'item_layout')]")
price=self.find(priceLocator).text
return float(price)
test_search.py
from selenium.webdriver.common.by import By
from appium.webdriver.common.mobileby import MobileBy #是对By的补充,只能使用在app中
from page_object.page.BasePage import BasePage
class SelectedPage(BasePage):
def addDefault(self):
return self
def gotoHS(self):
self.findByText("沪深").click()
return self
def getPriceByName(self,name):
priceLocator=(By.XPATH,"//*[contains(@resource-id,'portfolio_stockName') and @text='%s']" %name+
"/../../../..//*[contains(@resource-id,'item_layout')]")
price=self.find(priceLocator).text
return float(price)
test_selected.py
from page_object.page.MainPage import MainPage
from page_object.page.app import App
class TestSelected(object):
mainPage:MainPage
@classmethod
def setup_class(cls):
cls.mainPage=App.main() #进入首页
def test_price(self):
assert self.mainPage.gotoSelected().gotoHS().getPriceByName("恒瑞医药")==78.88
使用yaml再次进行框架封装:
BasePage.py增加读取yaml的方法:loadStep
from page_object.driver.AndroidClient import AndroidClient
from appium.webdriver.webelement import WebElement
from selenium.webdriver.common.by import By
import yaml
class BasePage(object):
def __init__(self):
self.driver=self.getDriver()
@classmethod
def getDriver(cls):
cls.driver=AndroidClient.driver
return cls.driver #没想通
@classmethod
def getClient(cls):
return AndroidClient # 没想通
def find(self,kv)->WebElement:
#todo:处理弹框
return self.driver.find_element(*kv)
def findByText(self,text)->WebElement:
return self.find((By.XPATH,"//*[@text='%s']" %text))
def loadStep(self,po_path,key,**kwargs):
file=open(po_path,'r')
po_data=yaml.load(file)
po_method=po_data[key]
for step in po_method:
element=self.driver.find_element(by=step['by'],value=step['locator'])
action=str(step['action']).lower() #这里把action的值转化成了小写
#todo:定位失败,多数是弹框,try catch后进入 一个弹框处理
if action =="click": #写上小写,yaml文件中也要写上小写
element.click()
elif action=="sendkeys": #这里要写小写,ymal文件中也要写上小写
text=str(step['text'])
for k,v in kwargs.items():
text=text.replace("$%s" %k, v)
print("update text:%s "% (text))
element.send_keys(text)
else:
print("UNKONW COMMAND %s" % step)
LoginPage.yaml
loginByPassword:
- locator: tv_login_with_account
by: id
action: click
- locator: login_account
by: id
action: sendkeys
text: $var1
- locator: login_password
by: id
action: sendkeys
text: $var2
- locator: button_next
by: id
action: click
LoginPage.py代码变化:
from selenium.webdriver.common.by import By
from page_object.page.BasePage import BasePage
class LoginPage(BasePage):
_back_locator=(By.ID,"iv_action_back")
_phone_login=(By.ID,"iv_login_phone")
_wx_login=(By.ID,"iv_login_wx")
_weibo_login=(By.ID,"iv_login_weibo")
_qq_login=(By.ID,"iv_login_qq")
_other_login=(By.ID,"login_more")
_register_phone_number=(By.ID,"register_phone_number")
_register_code=(By.ID,"register_code")
_button_next=(By.ID,"button_next")
_tv_login_with_account=(By.ID,"tv_login_with_account")
_login_account=(By.ID,"login_account")
_login_password=(By.ID,"login_password")
_error_msg=(By.ID,"md_content")
def loginByWX(self):
return self
def loginByMSG(self,phone,code):
return self
def loginByPassword(self, account, password):
self.loadStep("../data/LoginPage.yaml","loginByPassword",var1=account,var2=password)
return self
def loginSuccessByPassword(self,account,password):
from page_object.page.MainPage import MainPage #为什么会这样?
return MainPage()
def back(self):
self.find(self._back_locator).click()
from page_object.page.ProfilePage import ProfilePage #为什么会这样?
return ProfilePage()
def getErrorMsg(self):
msg= self.find(self._error_msg).text
self.findByText("确定").click()
return msg
MainPage.yaml:
gotoProfile:
- by: id
locator: user_profile_icon
action: click
MainPage.py:
from selenium.webdriver.common.by import By
from page_object.page.BasePage import BasePage
from page_object.page.ProfilePage import ProfilePage
from page_object.page.SelectedPage import SelectedPage
from page_object.page.SearchPage import SearchPage
class MainPage(BasePage):
#_profile_button=(By.ID,"user_profile_icon")
_search_button=(By.ID,"tv_search")
def gotoSelected(self):
zixuan = (By.XPATH, "//*[@text='自选']")
self.find(zixuan) # self.driver.find_element(By.XPATH,"//*[@text='自选']")
self.find(zixuan).click()
return SelectedPage()
def gotoSearch(self):
self.find(self._search_button).click()
return SearchPage()
def gotoProfile(self):
#self.find(MainPage._profile_button).click()
self.loadStep("../data/MainPage.yaml","gotoProfile") #使用yaml进行改造
return ProfilePage()
Profile.yaml
gotoLogin:
- by: id
locator: iv_login_phone
action: click
Profile.py:
from selenium.webdriver.common.by import By
from page_object.page.BasePage import BasePage
from page_object.page.LoginPage import LoginPage
class ProfilePage(BasePage):
#_phone_login = (By.ID, "iv_login_phone")
def gotoLogin(self):
#self.find(self._phone_login).click()
self.loadStep("../data/ProfilePage.yaml","gotoLogin")
return LoginPage()
使用yaml做一次分离后,测试用例没有任何变化只有page页面发生变化