├── README.md
├── driver
├── Appium.py
└── __init__.py
├── page
├── __init__.py
├── base_page.py
├── portfolio.py
├── search.py
├── stock.py
├── stock_group.py
└── xueqiu.py
├── temp
├── 1
│ ├── 11
│ │ ├── conftest.py
│ │ └── test_demo.py
│ ├── conftest.py
│ └── test_demo1.py
├── __init__.py
├── demo2
│ ├── BaseDemo.py
│ └── __init__.py
└── demo22
│ ├── 1.yaml
│ ├── __init__.py
│ └── test_children.py
├── test_apidemo.py
├── test_h5.py
├── test_ios.py
├── test_uicatalog.py
├── test_xueqiu.py
└── testcase
├── __init__.py
├── test_portfolio.py
├── test_stock_group.py
├── test_ut.py
└── test_xueqiu.py
/README.md:
--------------------------------------------------------------------------------
1 | # AppiumDemo8_Android
2 |
--------------------------------------------------------------------------------
/driver/Appium.py:
--------------------------------------------------------------------------------
1 | from appium import webdriver
2 | from appium.webdriver.webdriver import WebDriver
3 |
4 |
5 | class Appium(object):
6 |
7 |
8 | driver =None
9 | "@type driver: WebDriver"
10 |
11 | #这个办法只适合python3.5以上
12 | #driver: WebDriver = None
13 |
14 | @classmethod
15 | def getDriver(cls):
16 | return cls.driver
17 |
18 | @classmethod
19 | def initDriver(cls):
20 | print("setup")
21 | caps = {}
22 | caps["platformName"] = "android"
23 | caps["deviceName"] = "demo"
24 | caps["udid"]="192.168.59.101:5555"
25 | caps["appPackage"] = "com.xueqiu.android"
26 | caps["appActivity"] = ".view.WelcomeActivityAlias"
27 | caps["autoGrantPermissions"] = True
28 | caps["automationName"] = "UiAutomator2"
29 |
30 | cls.driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
31 | cls.driver.implicitly_wait(6)
--------------------------------------------------------------------------------
/driver/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seveniruby/AppiumDemo8_Android/7a2ed3be27ed6cb27bd4e30e13d48cc8f34aa654/driver/__init__.py
--------------------------------------------------------------------------------
/page/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seveniruby/AppiumDemo8_Android/7a2ed3be27ed6cb27bd4e30e13d48cc8f34aa654/page/__init__.py
--------------------------------------------------------------------------------
/page/base_page.py:
--------------------------------------------------------------------------------
1 | from appium.webdriver import WebElement
2 | from appium.webdriver.common.mobileby import MobileBy
3 | from lxml.html import Element
4 | from selenium.webdriver.common.by import By
5 |
6 | from driver.Appium import Appium
7 | from lxml import etree
8 |
9 | class BasePage(object):
10 |
11 | def __init__(self):
12 | pass
13 |
14 | @classmethod
15 | def byAndroid(self, text=None, id=None):
16 | text_selector=""
17 |
18 | if(text!=None):
19 | text_selector="@text='" + text + "'"
20 | if (id != None):
21 | id_selector = "contains(@resource-id, '" + id + "')"
22 | return (MobileBy.ANDROID_UIAUTOMATOR, 'new UiSelector().resourceId("' + id + '").text("' + text + '")')
23 | #return "//*[" + text_selector + " and " + id_selector + "]"
24 | else:
25 | return (MobileBy.ANDROID_UIAUTOMATOR,'new UiSelector().text("'+text+'")')
26 | #return "//*[" + text_selector + "]"
27 |
28 |
29 | @classmethod
30 | def byAttribute(self, text=None, id=None):
31 | text_selector=""
32 |
33 | if(text!=None):
34 | text_selector="@text='" + text + "'"
35 | if (id != None):
36 | id_selector = "contains(@resource-id, '" + id + "')"
37 | #return 'new UiSelector().resourceId("' + id + '").text("' + text + '")'
38 | return "//*[" + text_selector + " and " + id_selector + "]"
39 | else:
40 | #return 'new UiSelector().text("'+text+'")'
41 | return "//*[" + text_selector + "]"
42 |
43 |
44 | def findBy(self, by=By.ID, value=None):
45 | try:
46 | return Appium.getDriver().find_element(by, value)
47 | except:
48 | self.exception_handle2()
49 | return Appium.getDriver().find_element(by, value)
50 |
51 | def find(self, locate) -> WebElement:
52 | return self.findBy(*locate)
53 |
54 | def findAll(self, locate) -> []:
55 | return Appium.getDriver().find_elements(*locate)
56 |
57 | def exception_handle(self):
58 | self.black_words = [self.byAttribute(text="好的"), self.byAttribute(text="下次再说")]
59 |
60 | for w in self.black_words:
61 | elements = Appium.getDriver().find_elements(By.XPATH, w)
62 | if len(elements) > 0:
63 | elements[0].click()
64 | return Appium.getDriver().find_element(By.XPATH, w)
65 |
66 |
67 | def exception_handle2(self):
68 | self.black_words = [self.byAttribute(text="好的"), self.byAttribute(text="下次再说")]
69 |
70 | #todo: 优化弹框处理逻辑,发现toast,自动发现兼容性问题等。。。
71 | page_source=Appium.getDriver().page_source
72 | print(page_source)
73 | #parser = etree.XMLParser(encoding='utf-8')
74 | xml=etree.XML(str(page_source).encode("utf-8"))
75 | for w in self.black_words:
76 | print(w)
77 | if(len(xml.xpath(w))>0):
78 | Appium.getDriver().find_element(By.XPATH, w).click()
79 |
--------------------------------------------------------------------------------
/page/portfolio.py:
--------------------------------------------------------------------------------
1 | from selenium.webdriver.common.by import By
2 |
3 | from page.base_page import BasePage
4 | from page.search import Search
5 |
6 |
7 | class Portfolio(BasePage):
8 | _search_button=(By.ID, "action_create_cube")
9 | def toSearch(self):
10 | self.find(self._search_button).click()
11 | return Search()
--------------------------------------------------------------------------------
/page/search.py:
--------------------------------------------------------------------------------
1 | from appium.webdriver.common.mobileby import MobileBy
2 |
3 | from driver.Appium import Appium
4 | from page.base_page import BasePage
5 |
6 |
7 | class Search(BasePage):
8 | _user=(MobileBy.XPATH, "//*[@text='用户']")
9 | _username=(MobileBy.ID, "user_name")
10 | _stockName = (MobileBy.ID, "stockName")
11 | _search = (MobileBy.ID, "search_input_text")
12 | _cancel=(MobileBy.XPATH, "//*[@text='取消']")
13 |
14 | _follow=(MobileBy.ID, "com.xueqiu.android:id/follow_btn")
15 | _followed = (MobileBy.ID, "com.xueqiu.android:id/followed_btn")
16 |
17 | def search(self, keyword):
18 | self.find(self._search).send_keys(keyword)
19 | return self
20 |
21 | def getUserName(self):
22 | self.find(self._user).click()
23 | self.find(self._username).text
24 |
25 |
26 |
27 | def getStocks(self):
28 | return self.find(self._stockName).text
29 |
30 | def cancel(self):
31 | self.find(self._cancel).click()
32 |
33 | def followFirst(self):
34 | elements=self.findAll(self._follow)
35 | if len(elements)==2:
36 | elements[0].click()
37 |
38 | return self
39 |
--------------------------------------------------------------------------------
/page/stock.py:
--------------------------------------------------------------------------------
1 | from appium.webdriver.common.mobileby import MobileBy
2 | from appium.webdriver.common.touch_action import TouchAction
3 | from selenium.webdriver.common.by import By
4 |
5 | from driver.Appium import Appium
6 | from page.portfolio import Portfolio
7 |
8 |
9 | class Stock(Portfolio):
10 |
11 | _name=(By.ID, "com.xueqiu.android:id/portfolio_stockName")
12 | _us=(By.XPATH, "//*[@text='美股' and contains(@resource-id, 'text')]")
13 |
14 | _all=Portfolio.byAndroid(text="全部")
15 |
16 | def getNameByUS(self):
17 | self.find(self._us).click()
18 | x=[]
19 | for e in self.findAll(self._name):
20 | x.append(e.text)
21 | return x
22 |
23 | def getNameByAll(self):
24 | self.find(self._all).click()
25 | x=[]
26 | for e in self.findAll(self._name):
27 | x.append(e.text)
28 | return x
29 |
30 | def getNameByGroup(self, name):
31 | pass
32 |
33 |
34 | def delete(self, name, group_name=""):
35 | if group_name!="":
36 | self.find((By.XPATH, self.byAttribute(text=group_name))).click()
37 |
38 | print(Appium.getDriver().page_source)
39 | element=self.find((MobileBy.ANDROID_UIAUTOMATOR,
40 | 'new UiSelector().resourceId("com.xueqiu.android:id/portfolio_stockName").text("'+name+'")'))
41 | TouchAction(Appium.getDriver()).long_press(el=element).perform()
42 | self.find((By.XPATH, self.byAttribute(text='删除'))).click()
43 |
44 |
45 |
--------------------------------------------------------------------------------
/page/stock_group.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | class StockGroup(object):
4 |
5 | def add(self, name):
6 |
7 | return self
8 |
9 | def delete(self,name ):
10 | return self
11 |
12 | def sort(self, name=[]):
13 | return self
14 |
15 | def getGroups(self):
16 | return ["n1", "n2"]
17 |
18 | def toGroup(self, group):
19 | return self
20 |
--------------------------------------------------------------------------------
/page/xueqiu.py:
--------------------------------------------------------------------------------
1 | from selenium.webdriver.common.by import By
2 |
3 | from driver.Appium import Appium
4 | from page.base_page import BasePage
5 | from page.portfolio import Portfolio
6 | from page.search import Search
7 | from page.stock import Stock
8 |
9 |
10 | class Xueqiu(BasePage):
11 | _search=(By.ID, "home_search")
12 | _portfolio=(By.XPATH,"//*[@text='自选' and contains(@resource-id, 'tab_name')]")
13 | def __init__(self):
14 | self.loaded()
15 |
16 | def toSearch(self):
17 | self.find(self._search).click()
18 | return Search()
19 |
20 | def toPortfolio(self):
21 | self.find(self._portfolio).click()
22 | return Stock()
23 |
24 | def loaded(self):
25 | locations = ["x", "y"]
26 | while locations[-1] != locations[-2]:
27 | element = self.find(self._portfolio)
28 | print(element)
29 | locations.append(element.location)
30 | print(locations)
--------------------------------------------------------------------------------
/temp/1/11/conftest.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | import logging
3 |
4 | logging.basicConfig(level=logging.DEBUG)
5 |
6 |
7 | @pytest.fixture(scope="class")
8 | def username11():
9 | print("username 11 module 11")
10 | return "module username 11"
--------------------------------------------------------------------------------
/temp/1/11/test_demo.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | import logging
3 |
4 | class TestDemo(object):
5 | def test_demo1(self, username):
6 | print(username)
7 |
8 | def test_demo2(self, username11):
9 | logging.getLogger().info('boo %s', 'arg')
10 | print(username11)
11 | logging.info("xxxxx")
12 | logging.debug("ddd")
--------------------------------------------------------------------------------
/temp/1/conftest.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | @pytest.fixture(scope="module")
4 | def username():
5 | print("username module 1")
6 | return "module username 1"
--------------------------------------------------------------------------------
/temp/1/test_demo1.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | import logging
3 | import time
4 |
5 | logging.basicConfig(level=logging.DEBUG)
6 | loger=logging.getLogger("xxx")
7 | class TestDemo(object):
8 |
9 | def test_1(self):
10 | log = logging.getLogger('test_1')
11 | time.sleep(1)
12 | log.debug('after 1 sec')
13 | time.sleep(1)
14 | log.debug('after demo2 sec')
15 | time.sleep(1)
16 | log.debug('after 3 sec')
17 | assert 1, 'should pass'
18 |
19 |
20 |
--------------------------------------------------------------------------------
/temp/__init__.py:
--------------------------------------------------------------------------------
1 | import logging
2 | logging.basicConfig(level=logging.DEBUG)
--------------------------------------------------------------------------------
/temp/demo2/BaseDemo.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | import logging
3 |
4 | class BaseDemo(object):
5 | def setup(self):
6 | logging.basicConfig(level=logging.DEBUG)
7 | print("setup BaseDemo")
8 |
9 |
--------------------------------------------------------------------------------
/temp/demo2/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seveniruby/AppiumDemo8_Android/7a2ed3be27ed6cb27bd4e30e13d48cc8f34aa654/temp/demo2/__init__.py
--------------------------------------------------------------------------------
/temp/demo22/1.yaml:
--------------------------------------------------------------------------------
1 | - [1, 2]
2 | - [3, 4]
--------------------------------------------------------------------------------
/temp/demo22/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seveniruby/AppiumDemo8_Android/7a2ed3be27ed6cb27bd4e30e13d48cc8f34aa654/temp/demo22/__init__.py
--------------------------------------------------------------------------------
/temp/demo22/test_children.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from temp.demo2.BaseDemo import BaseDemo
4 | import yaml
5 | import logging
6 |
7 |
8 | def get_data():
9 | return yaml.load(open("1.yaml", 'r'))
10 |
11 |
12 | class TestChildren(BaseDemo):
13 | def setup(self):
14 | super().setup()
15 | print("setup Children")
16 | self.data=[(1, 2), (3, 4)]
17 |
18 | def test_demo(self):
19 | print("demo")
20 |
21 | @pytest.mark.parametrize("a, b", get_data())
22 | def test_data(self, a, b):
23 | logging.info(b)
24 | print(a)
25 |
26 |
27 |
--------------------------------------------------------------------------------
/test_apidemo.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | import unittest
3 | from appium import webdriver
4 | from time import sleep
5 |
6 | from appium.webdriver.common.touch_action import TouchAction
7 | from selenium.webdriver.support.wait import WebDriverWait
8 |
9 |
10 | class TestApiDemo(unittest.TestCase):
11 | def setUp(self):
12 | print("setup")
13 | caps = {}
14 | caps["platformName"] = "android"
15 | caps["deviceName"] = "demo"
16 | #caps["appPackage"] = "com.example.android.apis"
17 | caps["appPackage"] = "io.appium.android.apis"
18 | caps["appActivity"] = ".ApiDemos"
19 | caps["autoGrantPermissions"] = "true"
20 | caps["automationName"] = "UiAutomator2"
21 | caps["newCommandTimeout"] = 600
22 |
23 | self.driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
24 | self.driver.implicitly_wait(10)
25 |
26 |
27 | def test_toast(self):
28 | self.driver.find_element_by_accessibility_id("Views").click()
29 | #self.driver.find_element_by_accessibility_id("Popup Menu").click()
30 | self.driver.find_element_by_android_uiautomator(
31 | 'new UiScrollable(new UiSelector().scrollable(true).instance(0)).getChildByText(new UiSelector().className("android.widget.TextView"), "Popup Menu")'
32 | ).click()
33 | self.driver.find_element_by_accessibility_id("Make a Popup!").click()
34 | self.driver.find_element_by_xpath("//*[@text='Search']").click()
35 | print(self.driver.find_element_by_xpath("//*[@class='android.widget.Toast']").text)
36 | print(self.driver.find_element_by_xpath("//*[@package='com.android.settings']").text)
37 | print(self.driver.find_element_by_xpath("//*[contains(@text, 'Clicked')]").text)
38 |
39 | def test_toast_not_found(self):
40 | self.driver.find_element_by_accessibility_id("Views").click()
41 | #self.driver.find_element_by_accessibility_id("Popup Menu").click()
42 | self.driver.find_element_by_android_uiautomator(
43 | 'new UiScrollable(new UiSelector().scrollable(true).instance(0)).getChildByText(new UiSelector().className("android.widget.TextView"), "Popup Menu")'
44 | ).click()
45 | self.driver.find_element_by_accessibility_id("Make a Popup!").click()
46 | self.driver.find_element_by_xpath("//*[@text='Search']").click()
47 |
48 |
49 | def test_webview_sim_simple(self):
50 | self.driver.find_element_by_accessibility_id("Views").click()
51 | self.driver.find_element_by_android_uiautomator(
52 | 'new UiScrollable(new UiSelector().scrollable(true).instance(0)).getChildByText(new UiSelector().className("android.widget.TextView"), "WebView")'
53 | ).click()
54 | self.driver.find_element_by_accessibility_id("Hello World! - 1").click()
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/test_h5.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | from appium import webdriver
3 |
4 | class TestH5(unittest.TestCase):
5 | def setUp(self):
6 | caps={}
7 | caps["platformName"]="android"
8 | caps["deviceName"]="seveniruby"
9 | #caps["browserName"]="chrome"
10 | caps["browserName"]="Browser"
11 | caps["noReset"]="true"
12 | caps["fullReset"]="false"
13 | caps["forceMjsonwp"]="true"
14 | caps["dontStopAppOnReset"]="true"
15 |
16 | self.driver=webdriver.Remote("http://127.0.0.1:4723/wd/hub", caps)
17 | self.driver.implicitly_wait(10)
18 |
19 | def test_main(self):
20 |
21 | self.driver.get("https://danjuanapp.com/my-money?channel=1300100158&refer=xq_trade")
22 | self.driver.find_element_by_css_selector(".btns .blank").click()
23 | self.driver.find_element_by_css_selector(".pass_switch").click()
24 | self.driver.find_element_by_name("telno").send_keys("15600534760")
25 | self.driver.find_element_by_name("pass").send_keys("password")
26 | self.driver.find_element_by_id("next").click()
27 |
--------------------------------------------------------------------------------
/test_ios.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | import unittest
3 | from appium import webdriver
4 | from time import sleep
5 |
6 | from appium.webdriver.common.touch_action import TouchAction
7 | from selenium.webdriver.support.wait import WebDriverWait
8 |
9 |
10 | class TestIOS(unittest.TestCase):
11 | loaded = False
12 |
13 | def setUp(self):
14 | pass
15 |
16 |
17 | def test_uicatalog_sim(self):
18 |
19 | print("setup")
20 | caps = {}
21 | caps["platformName"] = "ios"
22 | caps["platformVersion"] = "12.1"
23 | caps["deviceName"] = "iPhone X"
24 | caps["app"] = '/Users/seveniruby/Library/Developer/Xcode/DerivedData/UICatalog-ftyzdbgapjmxxobezrnrxsshpdqh/' \
25 | 'Build/Products/Debug-iphonesimulator/UICatalog.app'
26 |
27 | if TestIOS.loaded == True:
28 | caps["noReset"] = "true"
29 |
30 | self.driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
31 | self.driver.implicitly_wait(10)
32 | loaded = True
33 |
34 |
35 | print(self.driver.page_source)
36 | self.driver.find_element_by_id("Buttons").click()
37 | self.driver.back()
38 | self.driver.find_element_by_accessibility_id("Buttons").click()
39 |
40 | def test_uicatalog_real_by_url(self):
41 | caps = {}
42 | caps["platformName"] = "ios"
43 | caps["automationName"] = "xcuitest"
44 | caps["deviceName"] = "Uzumaki的iPhone"
45 | caps["udid"]="auto"
46 | caps["app"] = '/Users/seveniruby/Library/Developer/Xcode/DerivedData/UICatalog-dfavfehsvaabuqdpmxouzqphclvl/' \
47 | 'Build/Products/Debug-iphoneos/UICatalog.app'
48 | caps["xcodeOrgId"]="96NJEQL7Y2"
49 | caps["xcodeSigningId"]="iPhone Developer"
50 | caps["webDriverAgentUrl"]="http://192.168.0.102:8100"
51 |
52 | self.driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
53 | self.driver.implicitly_wait(10)
54 | print(self.driver.page_source)
55 |
56 | def test_uicatalog_real(self):
57 | caps = {}
58 | caps["platformName"] = "ios"
59 | caps["automationName"] = "xcuitest"
60 | caps["deviceName"] = "Uzumaki的iPhone"
61 | caps["udid"]="auto"
62 | caps["app"] = '/Users/seveniruby/Library/Developer/Xcode/DerivedData/UICatalog-dfavfehsvaabuqdpmxouzqphclvl/' \
63 | 'Build/Products/Debug-iphoneos/UICatalog.app'
64 | caps["xcodeOrgId"]="96NJEQL7Y2"
65 | caps["xcodeSigningId"]="iPhone Developer"
66 | #加速,绕过构建
67 | caps["usePrebuiltWDA"]="true"
68 |
69 | self.driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
70 | self.driver.implicitly_wait(10)
71 | print(self.driver.page_source)
72 |
73 |
--------------------------------------------------------------------------------
/test_uicatalog.py:
--------------------------------------------------------------------------------
1 | # This sample code uses the Appium python client
2 | # pip install Appium-Python-Client
3 | # Then you can paste this into a file and simply run with Python
4 |
5 | import unittest
6 | from appium import webdriver
7 | from appium.webdriver.webelement import WebElement
8 |
9 |
10 | class TestUicatalog(unittest.TestCase):
11 | def setUp(self):
12 | caps = {}
13 | caps["platformName"] = "ios"
14 | caps["platformVersion"] = "12.1"
15 | caps["deviceName"] = "iPhone X"
16 | caps["app"] = "/Users/seveniruby/Library/Developer/Xcode/DerivedData/UICatalog-dfavfehsvaabuqdpmxouzqphclvl/Build/Products/Debug-iphonesimulator/UICatalog.app"
17 |
18 | self.driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", caps)
19 |
20 | def test_buttons(self):
21 | el2 = self.driver.find_element_by_accessibility_id("Buttons")
22 | el2.click()
23 | print(self.driver.page_source)
24 | self.driver.find_element_by_accessibility_id("UICatalog").click()
25 |
26 | def tearDown(self):
27 | self.driver.quit()
--------------------------------------------------------------------------------
/test_xueqiu.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | from time import sleep
3 |
4 | from appium.webdriver.common.mobileby import MobileBy
5 | from appium.webdriver.common.touch_action import TouchAction
6 | from selenium.webdriver.support.wait import WebDriverWait
7 | from selenium.webdriver.support import expected_conditions
8 |
9 | from page.search import Search
10 | from driver.Appium import Appium
11 | from page.xueqiu import Xueqiu
12 |
13 |
14 | class TestXueqiu(unittest.TestCase):
15 | loaded = False
16 |
17 | def setUp(self):
18 | Appium.initDriver()
19 | print(Appium.driver)
20 |
21 |
22 | def test_add_stock(self):
23 | self.driver.find_element_by_id("tv_search").click()
24 | self.driver.save_screenshot("screenshot/tv_search.png")
25 | self.driver.find_element_by_id("search_input_text").send_keys("pdd")
26 | self.driver.save_screenshot("screenshot/search_input_text.png")
27 |
28 | print(self.driver.find_element_by_id("add_attention") \
29 | .find_element_by_class_name("android.widget.TextView") \
30 | .get_attribute("resourceId"))
31 |
32 | if len(self.driver.find_elements_by_id("follow_btn")) > 0:
33 | self.driver.find_element_by_id("follow_btn").click()
34 | self.driver.find_element_by_xpath("//*[@text='下次再说']").click()
35 |
36 | def test_check_stock(self):
37 | for i in range(1, 5):
38 | element = self.driver.find_element_by_xpath(
39 | "//*[@text='自选' and contains(@resource-id, 'tab_name')]")
40 | print(element.location)
41 | element.text
42 | element.get_attribute("text")
43 | self.driver.find_element_by_xpath(
44 | "//*[@text='自选' and contains(@resource-id, 'tab_name')]").click()
45 | assert 1 == len(self.driver.find_elements_by_xpath(
46 | "//*[contains(@resource-id, 'portfolio_stockName') and @text='拼多多']"))
47 |
48 | def test_mobile(self):
49 | # self.driver.start_activity("com.android.calculator2", ".Calculator")
50 | print(self.driver.is_locked())
51 | self.driver.lock(5)
52 | self.driver.unlock()
53 | # self.driver.shake()
54 |
55 | def test_touch(self):
56 | self.loaded()
57 | self.driver.find_element_by_xpath(
58 | "//*[@text='自选' and contains(@resource-id, 'tab_name')]").click()
59 |
60 | element = self.driver.find_element_by_xpath("//*[@text='拼多多']")
61 | TouchAction(self.driver).long_press(element).perform()
62 | self.driver.find_element_by_xpath("//*[@text='删除']").click()
63 |
64 | def test_main_swipe(self):
65 | self.loaded()
66 | for i in range(1, 10):
67 | sleep(1)
68 | self.driver.swipe(start_x=1340, start_y=2000, end_x=200, end_y=600, duration=1000)
69 |
70 | def find(self, by, locator):
71 |
72 | try:
73 | self.driver.find_element(by, locator)
74 | except:
75 | keywords=[]
76 | for key in keywords:
77 | elements=self.driver.find_elements(key)
78 | if len(elements)>0:
79 | elements[0].click()
80 |
81 |
82 | def loaded(self):
83 | locations = ["x", "y"]
84 | while locations[-1] != locations[-2]:
85 | element = self.driver.find_element_by_xpath(
86 | "//*[@text='自选' and contains(@resource-id, 'tab_name')]")
87 | locations.append(element.location)
88 | print(locations)
89 |
90 | def test_battery(self):
91 | print(self.driver.execute_script("mobile:batteryInfo"))
92 |
93 | def test_shell(self):
94 | print(self.driver.execute_script("mobile:shell",
95 | {"command": "am",
96 | "args": ["start", "-n", "com.android.calculator2/.Calculator"]}))
97 |
98 | def test_webview_sim_image(self):
99 | self.loaded()
100 | self.driver.find_element_by_xpath("//*[@text='交易']").click()
101 | self.driver.find_element_by_accessibility_id("15da75b0b28c2b23feda8fe7").click()
102 |
103 |
104 | def test_webview_sim_h5(self):
105 | self.loaded()
106 | self.driver.find_element_by_xpath("//*[@text='交易']").click()
107 | WebDriverWait(self.driver, 10).until(
108 | expected_conditions.visibility_of_element_located(
109 | (MobileBy.ACCESSIBILITY_ID, "基金开户")))
110 | self.driver.switch_to.context("WEBVIEW_com.xueqiu.android")
111 | print(self.driver.current_context)
112 | print(self.driver.page_source)
113 | self.driver.find_element_by_css_selector(".trade_home_agu_3ki").click()
114 |
115 | def test_search(self):
116 | xueqiu=Xueqiu()
117 | search=xueqiu.toSearch()
118 | search.search("pdd")
119 | assert search.getStocks() == "拼多多"
120 |
121 | def test_search_username(self):
122 | xueqiu=Xueqiu()
123 | search=xueqiu.toSearch()
124 | search.search("seveniruby")
125 | assert search.getUserName() == "seveniruby"
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/testcase/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seveniruby/AppiumDemo8_Android/7a2ed3be27ed6cb27bd4e30e13d48cc8f34aa654/testcase/__init__.py
--------------------------------------------------------------------------------
/testcase/test_portfolio.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | import unittest
3 |
4 | from driver.Appium import Appium
5 | from page.xueqiu import Xueqiu
6 |
7 |
8 | class TestPortfolio(unittest.TestCase):
9 |
10 | def setUp(self):
11 | #todo: 数据的初始化
12 | Appium.initDriver()
13 | self.xueqiu=Xueqiu()
14 | self.stock=self.xueqiu.toPortfolio()
15 |
16 | def test_list(self):
17 | print(self.stock.getNameByUS())
18 |
19 |
20 | def test_add(self):
21 | self.stock.toSearch().search("alibaba").followFirst().cancel()
22 | assert "阿里巴巴" in self.stock.getNameByUS()
23 |
24 | def test_delete(self):
25 | self.stock.delete("拼多多", "美股")
26 | assert "拼多多" not in self.stock.getNameByUS()
27 |
28 | def test_delete_all(self):
29 |
30 | #todo: xpath定位bug 确认是8.0系统上的android Uiautomator2 server的bug
31 | #todo: 使用接口清理数据是更高效的办法
32 |
33 | stocks=[]
34 | while True:
35 | stocks=self.stock.getNameByAll()
36 | if len(stocks)==0:
37 | break
38 | stock=stocks[0]
39 | print(stock)
40 | self.stock.delete(stock)
41 | #Appium.initDriver()
42 | #self.xueqiu = Xueqiu()
43 | #self.stock = self.xueqiu.toPortfolio()
44 |
45 | assert len(self.stock.getNameByAll())==0
46 |
--------------------------------------------------------------------------------
/testcase/test_stock_group.py:
--------------------------------------------------------------------------------
1 | from unittest import TestCase
2 |
3 | from page.stock_group import StockGroup
4 | import pytest
5 |
6 | from page.xueqiu import Xueqiu
7 |
8 |
9 | class TestStockGroup(object):
10 |
11 | def setup(self):
12 | # todo: 删除所有分组
13 | self.group = StockGroup()
14 | pass
15 |
16 | def test_add(self):
17 | self.group.add("demo")
18 | assert "demo" in self.group.getGroups()
19 |
20 | @pytest.mark.parametrize("group,name", [
21 | ("g1", "n1"),
22 | ("g2", "n2"),
23 | ("g3", "n3")
24 | ])
25 | def test_add(self, group, name):
26 | self.group.toGroup(group)
27 | self.group.add(name)
28 | assert name in self.group.getGroups()
29 |
30 | @pytest.mark.parametrize("name", ["1", "demo2", "中文名"])
31 | def test_delete(self, name):
32 | name = "demo2"
33 | assert name in self.group.add(name).getGroups()
34 | self.group.delete(name)
35 | assert name not in self.group.getGroups()
36 |
--------------------------------------------------------------------------------
/testcase/test_ut.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | from lxml import etree
4 |
5 | def test_xpath():
6 | import xml.etree.ElementTree as ET
7 |
8 | root = ET.fromstring('