Directory structure changes:
1. The Android client.py script has no changes:
#AndroidClient.py from appium.webdriver.webdriver import WebDriver from appium import webdriver class AndroidClient(object): driver:WebDriver @classmethod def installApp(cls)->WebDriver: caps={} #These are written to the configuration file #caps['app']='' caps['platformName']='android' caps['deviceName']='hogwarts' caps['appPackage']='com.xueqiu.android' caps['appActivity']=".view.WelcomeActivityAlias" #Solve the authorization problem of the first startup caps['autoGrantPermissions']='true' cls.driver=webdriver.Remote("http://localhost:4723/wd/hub",caps) cls.driver.implicitly_wait(15) return cls.driver @classmethod def restartApp(cls)->WebDriver: caps = {} # caps['app']='' caps['platformName'] = 'android' caps['deviceName'] = 'hogwarts' caps['appPackage'] = 'com.xueqiu.android' caps['appActivity'] = ".view.WelcomeActivityAlias" # Solve the authorization problem of the first startup caps['autoGrantPermissions'] = 'true' # In order to start faster and keep the previous data, the status of the last case can be saved. #caps['noReset']=True #When there are multiple devices, you need to specify the uuid of the device. # caps["udid"]="emulator-5554" caps['unicodeKeyboard']=True #Support Chinese input caps['resetKeyboard'] = True cls.driver = webdriver.Remote("http://localhost:4723/wd/hub", caps) cls.driver.implicitly_wait(15) return cls.driver
pages bag:
App.py implements the function of APP startup:
#App.py from page_objects.driver.AndroidClient import AndroidClient from page_objects.pages.Mainpage import MainPage from page_objects.pages.basepage import Basepage class App(Basepage): @classmethod def main(cls): cls.getClient().restartApp() return MainPage()
Basepage.py: some common basic operations of page
#basepage.py from selenium.webdriver.common.by import By from page_objects.driver.AndroidClient import AndroidClient from page_objects.driver.SeleniumClient import SeleniumClient from selenium.webdriver.remote.webelement import WebElement from appium.webdriver.webdriver import WebDriver class Basepage(object): def __init__(self): self.driver=self.getDriver() #driver in each instance @classmethod def getDriver(cls): #todo: #{multi platform testing: 1. When using method 1 and multi platform, call the unused Client according to the configuration item in the configuration file. 2. Method 2: write a web page - > selenium web, and let the web page test inherit this. 3. Step back to selenium. All driver s inherit selenium. # if True: # cls.driver=AndroidClient.driver # else: # cls.driver=SeleniumClient.driver #} cls.driver = AndroidClient.driver return cls.driver @classmethod def getClient(cls): return AndroidClient def find(self,kv)->WebElement: #Without return value, there is no way to reverse click and sendkeys when calling find. #todo: handle pop ups return self.driver.find_element(*kv) def findByText(self,text)->WebElement: return self.find((By.XPATH, "//*[@text='%s']" %text))
Mainpage.py: some operations of snowball APP Homepage
#Mainpage.py from page_objects.pages.SelectedPage import SelectedPage from page_objects.pages.basepage import Basepage from selenium.webdriver.common.by import By from page_objects.pages.Searchpage import Searchpage from page_objects.pages.ProfilePage import ProfilePage import time class MainPage(Basepage): _profile_button=(By.ID,"user_profile_icon") _search_button = (By.ID, "home_search") def gotoSelected(self): #Calling global driver object and using webdriver api to manipulate app #{original method #Self.driver.find'element'by'xpath ("/ / * [@ text ='optional ']) # Self.driver.find'element (by.xpath, "/ / * [@ text = 'optional']) # Self.driver.find'element'by'xpath ("/ / * [@ text ='optional ']). click() #} #{find() method #zixuan=(By.XPATH, "//*[@text = 'optional']) #self.find(zixuan) #self.find(zixuan).click() #} #{findByText() method zixuan="Optional" self.findByText(zixuan) self.findByText(zixuan).click() #} return SelectedPage() def gotohangqing(self): self.driver.find_element_by_xpath("//*[@ text = 'market'] ") self.driver.find_element_by_xpath("//*[@ text = 'market'] "). click() time.sleep(10) return hangqingpage() def gotoSearch(self) -> Searchpage: self.find(self._search_button).click() return Searchpage() def gotoprofile(self) ->ProfilePage: self.find(MainPage._profile_button).click() return ProfilePage()
Element positioning and operation of LoginPage.py landing page:
#LoginPage.py from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions from page_objects.pages.basepage import Basepage class LoginPage(Basepage): #The same set of test scripts tests different platforms, web and app. #todo:read form yaml, dynamically read different locators from yaml files according to different platforms _close_locator=(By.ID,"iv_close") _other_locator=(By.ID,"tv_login_by_phone_or_others") _weixin_locator=(By.ID,"rl_login_by_wx") _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") _close2_locator=(By.ID,"iv_action_back") _error_msg=(By.ID,"md_content") _error_sure_btn=(By.ID,"md_buttonDefaultPositive") _back_locator=(By.XPATH,"//*[contains(@resource-id,'iv_close')or contains(@resource-id,'iv_action_back')]") def loginByWX(self):#WeChat landing return self def loginByMSG(self,phone,code): #Mobile phone or other location pass def loginByPassword(self,account,password): self.find(self._other_locator).click() 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() return self pass def loginSuccessByPassword(self,account,password): from page_objects.pages.Mainpage import MainPage return MainPage() def back(self): self.find(self._back_locator).click() #WebDriverWait(self.driver,5).until(expected_conditions.presence_of_element_located(self._close_locator)) from page_objects.pages.ProfilePage import ProfilePage return ProfilePage() def getErrorMsg(self): msg=self.find(self._error_msg).text self.find(self._error_sure_btn).click() return msg
ProfilePage.py click the login page
#ProfilePage.py click the login page from selenium.webdriver.common.by import By from page_objects.pages.LoginPage import LoginPage from page_objects.pages.basepage import Basepage class ProfilePage(Basepage): def gotoLogin(self): clicklog=(By.ID,"tv_login") self.find(clicklog).click() return LoginPage()
Search page: search page.py
#Searchpage.py from selenium.webdriver.common.by import By from page_objects.pages.basepage import Basepage class Searchpage(Basepage): _edit_locator=(By.CLASS_NAME, "android.widget.EditText") def search(self,key): self.find(self._edit_locator).send_keys(key) return self #It can be called in chain, and always use.... def addToSelected(self,key): follow_button = (By.XPATH, "//*[contains(@resource-id,'stockCode')and contains(@text,'%s')]" % key + "/../../..//*[contains(@resource-id,'follow_btn')]") self.find(follow_button).click() return self def removeFromSelected(self,key): follow_button = (By.XPATH, "//*[contains(@resource-id,'stockCode')and contains(@text,'%s')]" % key + "/../../..//*[contains(@resource-id,'followed_btn')]") self.find(follow_button).click() return self def isExisted(self,key): follow_button=(By.XPATH,"//*[contains(@resource-id,'stockCode')and contains(@text,'%s')]"%key+ "/../../..//*[contains(@resource-id,'follow')]") id=self.find(follow_button).get_attribute("resourceId") print(id) return "followed_btn" in id def cancel(self): self.findByText("cancel").click() def searchByUser(self,key): pass def isFollowed(self): pass
Stock price information of optional page: SelectedPage.py
#SelectedPage.py from selenium.webdriver.common.by import By from page_objects.driver.AndroidClient import AndroidClient from page_objects.pages.basepage import Basepage class SelectedPage(Basepage): def addDefault(self): return self def getPriceByName(self,name): #price=self.driver.find_element_by_xpath("//*[contains(@resource-id,'portfolio_stockName') and (@text='"+name+"')]/../../..//*[contains(@resource-id,'portfolio_currentPrice')]").text priceLocate=(By.XPATH,"//*[contains(@resource-id,'portfolio_stockName') and (@text='%s')]/../../..//*[contains(@resource-id,'portfolio_currentPrice')]" %name) price=self.find(priceLocate).text return float(price) def gotohs(self): self.findByText("Shanghai and Shenzhen").click() return self
testcase: package of test case:
Test added stock: test selected page.py
#test_selected_page.py from page_objects.pages import Mainpage from page_objects.pages.App import App import pytest class TestSelected(object): mainPage:Mainpage @classmethod def setup_class(cls): cls.mainPage=App.main() def setup_method(self): self.mainPage: Mainpage =TestSelected.mainPage self.searchPage=self.mainPage.gotoSearch() def test_is_selected_stock(self): searchpage= self.searchPage.search("alibaba") assert searchpage.isExisted("BABA")==True assert searchpage.isExisted("1688") == False def test_is_follow_user(self): pass @pytest.mark.parametrize("key,code",[ #Data driven ("China Merchants Bank","SH60036"), ("Ping An Bank","SZ0001"), ("pingan","SH601318") ]) def test_is_selected_stock_hs(self,key,code): searchPage=self.searchPage.search(key) assert searchPage.isExisted(code)==False def teardown_method(self): self.searchPage.cancel() def test_add_stock_hs(self): key="China Merchants Bank" code="SH600036" self.searchPage.search(key) if self.searchPage.isExisted(code)==True: self.searchPage.removeFromSelected(code) self.searchPage.addToSelected(code) assert self.searchPage.isExisted(code)==True
Test login function: Test login.py
#test_login.py from page_objects.pages.App import App import pytest class TestLogin(object): @classmethod def setup_class(cls): cls.profilePage=App.main().gotoprofile() #Execute once to the profile page def setup_method(self): self.loginPage=self.profilePage.gotoLogin()#Execute once to loginpage page @pytest.mark.parametrize("user,pw,msg",[ ("150265983481","123456","Phone number"), ("15026598348", "123456", "Password error") ]) def test_login_password(self,user,pw,msg): self.loginPage.loginByPassword(user,pw) assert msg in self.loginPage.getErrorMsg() def teardown_method(self): self.loginPage.back()
Test selected page stock price: test selected page.py
#test_selected_page.py from page_objects.pages import Mainpage from page_objects.pages.App import App import pytest class TestSelected(object): mainPage:Mainpage @classmethod def setup_class(cls): cls.mainPage=App.main() def setup_method(self): self.mainPage: Mainpage =TestSelected.mainPage self.searchPage=self.mainPage.gotoSelected() def test_price(self): assert self.searchPage.gotohs().getPriceByName("Erie shares")==32.10 def teardown_method(self): self.searchPage.cancel()