移動(dòng)端測(cè)試

知識(shí)概覽

一富雅、 移動(dòng)端測(cè)試是什么

移動(dòng)端測(cè)試是指對(duì)移動(dòng)應(yīng)用進(jìn)行的測(cè)試,即實(shí)體的特性滿足需求的程度橄镜。

二括饶、 移動(dòng)端測(cè)試分類

1. app功能測(cè)試

業(yè)務(wù)邏輯正確性測(cè)試:依據(jù)產(chǎn)品文檔設(shè)計(jì)測(cè)試用例,加上隱性需求用例

兼容性測(cè)試:

1. 系統(tǒng)版本:android:原生安卓系統(tǒng):4.4 5.8恕洲。定制版本:小米塔橡、華為、魅族..IOS:原生系統(tǒng):5.0.霜第。葛家。2. 屏幕分辨率:720*1280 1928*1888.,圖片(根據(jù)分辨率做一些圖片)3. 網(wǎng)絡(luò)狀態(tài):2g 3g 4g 5g wifi

異常測(cè)試

1.熱啟動(dòng)應(yīng)用:應(yīng)用由后臺(tái)轉(zhuǎn)換為前臺(tái)的過程? 考慮:1.仍然展示退到后臺(tái)時(shí)的頁面2.希望初始化為首頁2.網(wǎng)絡(luò)切換和中斷恢復(fù)? ①網(wǎng)絡(luò)切換:wifi->2g 4g->3g應(yīng)用正趁诶啵可用狀態(tài)? ②中斷恢復(fù):4g-→斷網(wǎng)-→4g(下載2M的應(yīng)用惦银,1%斷網(wǎng),恢復(fù)網(wǎng)絡(luò)(斷點(diǎn)續(xù)傳末誓,重新下載))3.電話和信息中斷恢復(fù)? ①電話:看視頻->電話接18分鐘->返回視頻app? ②信息:玩游戲一>通知欄一個(gè)消息->不影響游戲體驗(yàn)

升級(jí)安裝卸載測(cè)試:

升級(jí):臨近版本升級(jí)(1.0->1.1)跨版本升級(jí)(1.0->1.7)保證升級(jí)后app可用狀態(tài)安裝測(cè)試:首次安裝卸載后安裝霍蓋安裝保證app安裝后可用,安裝文件齊全

健壯性測(cè)試:

手機(jī)資源消耗:cpu內(nèi)存流量消耗:數(shù)據(jù)流量加載圖片原間消耗22M 圖片壓縮數(shù)據(jù)壓縮崩潰恢復(fù)測(cè)試:app閃退提示終止運(yùn)行等等保證自啟動(dòng)可用手動(dòng)啟動(dòng)可用

2. App自動(dòng)化測(cè)試

例子:app設(shè)計(jì)500條測(cè)試用例2個(gè)人5天用例中有300條是主流業(yè)務(wù)可以通過腳本實(shí)現(xiàn)完成

優(yōu)點(diǎn):

1.高效數(shù)據(jù)絕對(duì)正確2.不需要人工干預(yù)3.回歸測(cè)試

3. 安全測(cè)試

通過一些安全測(cè)試工具

二书蚪、市場(chǎng)招聘如何喇澡?

互聯(lián)網(wǎng)移動(dòng)場(chǎng)景下業(yè)務(wù)的爆發(fā),導(dǎo)致移動(dòng)端開發(fā)和測(cè)試人員需求量增大殊校,市場(chǎng)很缺移動(dòng)端的人才晴玖。 公司待遇:

app功能測(cè)試,一般1-3年的功能測(cè)試人員月薪8k-15k

app自動(dòng)化測(cè)試,一般1-3年的自動(dòng)化測(cè)試月薪13k-25k

三呕屎、主流的移動(dòng)端自動(dòng)化工具

支持語言支持系統(tǒng)跨平臺(tái)

RobotiumJava僅支持Android系統(tǒng)不支持跨應(yīng)用

MacacaJava,Python,Node.js支持Android和i0S系統(tǒng)支持跨應(yīng)用

AppiumJava,C#,Python,php,perl,ruby,Node.js支持Android和iOS系統(tǒng)支持跨應(yīng)用

自動(dòng)化工具選擇的關(guān)注點(diǎn):

足否支持native,webiew

是否支持獲取toast

是否支持跨應(yīng)用

四让簿、UIAutomatorviewer手機(jī)控件查看工具

1. 工具簡(jiǎn)介

用來掃描和分析Android應(yīng)用程序的UI控件的工具。

2. 如何使用

進(jìn)入SDK目錄下的tools目錄秀睛,打開uiautomatorviewer

電腦連接真機(jī)或打開android模擬器

啟動(dòng)待測(cè)試app

點(diǎn)擊uiautomatorviewer的左上角Device Screenshot,會(huì)生成app當(dāng)前頁面的UI控件截圖

選擇截圖上需要查看的控件尔当,即可瀏覽該控件的id,class,text,坐標(biāo)等信息


APP移動(dòng)端測(cè)試高級(jí)

一、Appium介紹

Appium是一個(gè)移動(dòng)端的自動(dòng)化框架蹂安,可用于測(cè)試原生應(yīng)用椭迎、移動(dòng)網(wǎng)頁應(yīng)用和混合型應(yīng)用,且是跨平臺(tái)的田盈⌒蠛牛可用于IOS和Android以及firefox的操作系統(tǒng)。

原生的應(yīng)用是指用android或ios的sdk編寫的應(yīng)用允瞧;移動(dòng)網(wǎng)頁應(yīng)用是指網(wǎng)頁應(yīng)用简软,類似于ios中safari應(yīng)用或者Chrome應(yīng)用或者類瀏覽器的應(yīng)用;混合應(yīng)用是指一種包裹webview的應(yīng)用,原生應(yīng)用于網(wǎng)頁內(nèi)容交互性的應(yīng)用述暂。

重要的是Appium是跨平臺(tái)的痹升,何為跨平臺(tái),意思就是可以針對(duì)不同的平臺(tái)用一套api來編寫測(cè)試用例贸典。

二视卢、環(huán)境搭建

主要幾個(gè)點(diǎn)如下:

image.png

1. appium安裝

直接解壓即可,打開Appium.exe

image.png

啟動(dòng)成功展示如下:

image.png

2. Appium庫(kù)安裝

# 安裝pip install Appium-Python-Client# 檢驗(yàn)是否成功piplist

三廊驼、Appium使用

1. 打開模擬器或真機(jī)的應(yīng)用

①打開手機(jī)應(yīng)用

②打開Appium

③創(chuàng)建一個(gè)python項(xiàng)目据过,并創(chuàng)建一個(gè)文件

④將下面代碼復(fù)制到文件中

⑤獲取當(dāng)前應(yīng)用包名和啟動(dòng)activity并修改文件

fromappiumimportwebdriver# server 啟動(dòng)參數(shù)desired_caps=dict()# 設(shè)備信息# 平臺(tái)信息,不區(qū)分大小寫desired_caps['platformName']='Android'# 系統(tǒng)版本妒挎,7.1.2可以寫[7 绳锅,7.1 , 7.1.2]desired_caps['platformVersion']='7.1.2'# 設(shè)備名稱酝掩,可以隨便寫鳞芙,但是不能亂寫,Android可以隨便寫期虾,但是ios必須正確的寫desired_caps['deviceName']='emulator-5554'# app的信息desired_caps['appPackage']='com.android.settings'desired_caps['appActivity']='.Settings'# 聲明我們的driver對(duì)象driver=webdriver.Remote('http://127.0.0.1:4723/wd/hub',desired_caps)driver.quit()

2. 腳本內(nèi)啟動(dòng)其他app

driver.start_activity(appPackage,appActivity)

3. 關(guān)閉app

driver.close_app()? # 關(guān)閉當(dāng)前操作的app原朝,不會(huì)關(guān)閉驅(qū)動(dòng)對(duì)象

4. 關(guān)閉驅(qū)動(dòng)對(duì)象

driver.quit()? # 關(guān)閉驅(qū)動(dòng)對(duì)象,同時(shí)關(guān)閉所有關(guān)聯(lián)的app

三镶苞、App基礎(chǔ)操作API

完成app自動(dòng)化需要一些基礎(chǔ)條件的支持喳坠,本節(jié)將講解APP初始化API。

3.1前置代碼

# server 啟動(dòng)參數(shù)desired_caps={}desired_caps['platformName']='Android'desired_caps['platformVersion']='5.1'desired_caps['deviceName']='192.168.56.101:5555'desired_caps['appPackage']='com.android.settings'desired_caps['appActivity']='.Settings'desired_caps['unicodeKeyboard']=Truedesired_caps['resetKeyboard']=True# 聲明driver對(duì)象driver=webdriver.Remote('http://127.0.0.1:4723/wd/hub',desired_caps)

3.2 安裝APK到手機(jī)

driver.install_app(app_path)

參數(shù):app_path:腳本機(jī)器中APK文件路徑

3.3 手機(jī)中移除APP

driver.remove_app(app_id)

參數(shù):app_id:需要卸載的app包名

3.4 判斷APP是否已安裝

driver.is_app_installed(bundle_id)

參數(shù):bundle_id: 可以傳入app包名,返回結(jié)果為True(已安裝) / False(未安裝)

3.5 發(fā)送文件到手機(jī)

importbase64data=str(base64.b64encode(data.encode('utf-8')),'utf-8')driver.push_file(path,data)參數(shù):

path:手機(jī)設(shè)備上的路徑(例如:/sdcard/a.txt)

data:文件內(nèi)數(shù)據(jù),要求base64編碼

Python3.x中字符都為unicode編碼茂蚓,而b64encode函數(shù)的參數(shù)為byte類型壕鹉,需要先轉(zhuǎn)碼剃幌;

生成的數(shù)據(jù)為byte類型,需要將byte轉(zhuǎn)換回去晾浴。

3.6 從手機(jī)中拉取文件

importbase64data=driver.pull_file(path)# 返回?cái)?shù)據(jù)為base64編碼print(str(base64.b64decode(data),'utf-8'))# base64解碼

參數(shù): path: 手機(jī)設(shè)備上的路徑

3.7獲取當(dāng)前屏幕內(nèi)元素結(jié)構(gòu)

driver.page_source

作用:返回當(dāng)前頁面的文檔結(jié)構(gòu)负乡,判斷特定的元素是否存在

四、手機(jī)控件查看工具uiautomatorviewer

4.1 工具簡(jiǎn)介

用來掃描和分析Android應(yīng)用程序的UI控件的工具.

4.1 如何使用

進(jìn)入SDK目錄下的tools目錄脊凰,打開uiautomatorviewer

電腦連接真機(jī)或打開android模擬器

啟動(dòng)待測(cè)試app

點(diǎn)擊uiautomatorviewer的左上角Device Screenshot,會(huì)生成app當(dāng)前頁面的UI控件截圖

image.png

選擇截圖上需要查看的控件抖棘,即可瀏覽該控件的id,class,text,坐標(biāo)等信息

image.png

五、APP元素定位操作

手工測(cè)試主要通過可見按鈕操作笙各,而自動(dòng)化是通過元素進(jìn)行交互操作钉答。

元素的基本定位基于當(dāng)前屏幕范圍內(nèi)展示的可見元素。

5.1 Appium常用元素定位方式

namevalue

idid屬性值

classclass屬性值

xpathxpath表達(dá)式

5.2 前置代碼

fromappiumimportwebdriver# server 啟動(dòng)參數(shù)desired_caps={}# 設(shè)備信息desired_caps['platformName']='Android'desired_caps['platformVersion']='5.1'desired_caps['deviceName']='192.168.56.101:5555'# app的信息desired_caps['appPackage']='com.android.settings'desired_caps['appActivity']='.Settings'# 聲明我們的driver對(duì)象driver=webdriver.Remote('http://127.0.0.1:4723/wd/hub',desired_caps)

5.3 通過id定位

方法:find_element_by_id(id_value) # id_value:為元素的id屬性值

業(yè)務(wù)場(chǎng)景:

1. 進(jìn)入設(shè)置頁面

2. 通過ID定位方式點(diǎn)擊搜索按鈕

代碼實(shí)現(xiàn):

driver.find_element_by_id("com.android.settings:id/search").click()driver.quit()

5.4 通過class定位

方法:find_element_by_class_name(class_value) # class_value:為元素的class屬性值

業(yè)務(wù)場(chǎng)景:

1. 進(jìn)入設(shè)置頁面

2. 點(diǎn)擊搜索按鈕

3. 通過class定位方式點(diǎn)擊輸入框的返回按鈕

代碼實(shí)現(xiàn):

# id 點(diǎn)擊搜索按鈕driver.find_element_by_id("com.android.settings:id/search").click()# class 點(diǎn)擊輸入框返回按鈕driver.find_element_by_class_name('android.widget.ImageButton').click()driver.quit()

5.5 通過xpath定位

方法:find_element_by_xpath(xpath_value) # xpath_value:為可以定位到元素的xpath語句

android端xptah常用屬性定位:

id ://*[contains(@resource-id,'com.android.settings:id/search')]

class ://*[contains(@class,'android.widget.ImageButton')]

text ://*[contains(@text,'WLA')]

模糊定位?contains(@key,value): value可以是部分值

業(yè)務(wù)場(chǎng)景:

1. 進(jìn)入設(shè)置頁面

2. 點(diǎn)擊WLAN菜單欄

代碼實(shí)現(xiàn):

# xpath 點(diǎn)擊WLAN按鈕driver.find_element_by_xpath("http://*[contains(@text,'WLA')]").click()

5.6 定位一組元素,注意element -> elements

應(yīng)用場(chǎng)景為元素值重復(fù)杈抢,無法通過元素屬性直接定位到某個(gè)元素数尿,只能通過elements方式來選擇,返回一個(gè)定位對(duì)象的列表.

5.7 通過id方式定位一組元素

方法: find_elements_by_id(id_value) # id_value:為元素的id屬性值

業(yè)務(wù)場(chǎng)景:

1. 進(jìn)入設(shè)置頁面

2. 點(diǎn)擊WLAN菜單欄(id定位對(duì)象列表中第1個(gè))

代碼實(shí)現(xiàn):

# 定位到一組元素title = driver.find_elements_by_id("com.android.settings:id/title")# 打印title類型惶楼,預(yù)期為listprint(type(title))# 取title返回列表中的第一個(gè)定位對(duì)象右蹦,執(zhí)行點(diǎn)擊操作title[0].click()

5.8 通過class方式定位一組元素

方法:find_elements_by_class_name(class_value) # class_value:為元素的class屬性值

業(yè)務(wù)場(chǎng)景:

1.進(jìn)入設(shè)置頁面

2.點(diǎn)擊WLAN菜單欄(class定位對(duì)象列表中第3個(gè))

代碼實(shí)現(xiàn):

title = driver.find_elements_by_class_name("android.widget.TextView")# 打印title類型,預(yù)期為listprint(type(title))# 取title返回列表中的第一個(gè)定位對(duì)象歼捐,執(zhí)行點(diǎn)擊操作title[3].click()for index, item in enumerate(ele_list):? print(index, item.text)? ```

5.9 通過xpath方式定位一組元素

方法:find_elements_by_xpath(xpath_value) # xpath_value:為可以定位到元素的xpath語句

業(yè)務(wù)場(chǎng)景:

1. 進(jìn)入設(shè)置頁面

2. 點(diǎn)擊WLAN菜單欄(xpath中class屬性定位對(duì)象列表中第3個(gè))

代碼實(shí)現(xiàn):

# 定位到一組元素title = driver.find_elements_by_xpath("http://*[contains(@class,'widget.TextView')]")# 打印title類型何陆,預(yù)期為listprint(type(title))# 取title返回列表中的第一個(gè)定位對(duì)象,執(zhí)行點(diǎn)擊操作title[3].click()

六豹储、WebDriverWait 顯示等待操作

在一個(gè)超時(shí)時(shí)間范圍內(nèi)贷盲,每隔一段時(shí)間去搜索一次元素是否存在,如果存在返回定位對(duì)象剥扣,如果不存在直到超時(shí)時(shí)間到達(dá)巩剖,報(bào)超時(shí)異常錯(cuò)誤。

方法:WebDriverWait(driver, timeout, poll_frequency).until(method)

參數(shù):

1.driver:手機(jī)驅(qū)動(dòng)對(duì)象

2.timeout:搜索超時(shí)時(shí)間

3.poll_frequency:每次搜索間隔時(shí)間钠怯,默認(rèn)時(shí)間為0.5s

4.method:定位方法(匿名函數(shù))

匿名函數(shù):

lambda x: x

等價(jià)于python函數(shù):

def test(x):

return x

使用示例:

WebDriverWait(driver,timeout,poll_frequency).until(lambdax:x.find_elements_by_id(id_value))

解釋:

1.x傳入值為:driver佳魔,所以才可以使用定位方法。

函數(shù)運(yùn)行過程:

1.實(shí)例化WebDriverWait類晦炊,傳入driver對(duì)象鞠鲜,之后driver對(duì)象被賦值給WebDriverWait的一個(gè)類變量:self._driver

2.until為WebDriverWait類的方法,until傳入method方法(即匿名函數(shù))断国,之后method方法會(huì)被傳入self._driver

3.搜索到元素后until返回定位對(duì)象贤姆,沒有搜索到函數(shù)until返回超時(shí)異常錯(cuò)誤.

業(yè)務(wù)場(chǎng)景:

1.進(jìn)入設(shè)置頁面

2.通過ID定位方式點(diǎn)擊搜索按鈕

代碼實(shí)現(xiàn):

fromselenium.webdriver.support.waitimportWebDriverWait# 導(dǎo)入WebDriverWait? 類# 超時(shí)時(shí)間為30s,每隔1秒搜索一次元素是否存在稳衬,如果元素存在返回定位對(duì)象并退出search_button=WebDriverWait(driver,30,1).until(lambdadriver:driver.find_element_by_id("com.android.settings:id/search"))search_button.click()driver.quit()

七庐氮、APP元素信息操作API

本節(jié)講介紹手機(jī)端元素信息的獲取以及基本的輸入操作。

7.1. 點(diǎn)擊元素

ele.click()

7.2.發(fā)送數(shù)據(jù)到輸入框

方法:send_keys(vaue) # value:需要發(fā)送到輸入框內(nèi)的文本

業(yè)務(wù)場(chǎng)景:

1.打開設(shè)置

2.點(diǎn)擊搜索按鈕

3.輸入內(nèi)容abc

代碼實(shí)現(xiàn):

# 點(diǎn)擊搜索按鈕driver.find_element_by_id("com.android.settings:id/search").click()# 定位到輸入框并輸入abcdriver.find_element_by_id("android:id/search_src_text").send_keys("abc")

重點(diǎn):大家可以將輸入的abc 改成 輸入中文宋彼,得到的結(jié)果:輸入框無任何值輸入且程序不會(huì)抱錯(cuò)

解決輸入中文問題:

1.server 啟動(dòng)參數(shù)增加兩個(gè)參數(shù)配置? ? ? desired_caps['unicodeKeyboard']=Truedesired_caps['resetKeyboard']=True2.再次運(yùn)行會(huì)發(fā)現(xiàn)運(yùn)行成功# 點(diǎn)擊搜索按鈕driver.find_element_by_id("com.android.settings:id/search").click()# 定位到輸入框并輸入abcdriver.find_element_by_id("android:id/search_src_text").send_keys("積云教育")

7.3. 清空輸入框內(nèi)容

方法:clear()

業(yè)務(wù)場(chǎng)景:

1.打開設(shè)置

2.點(diǎn)擊搜索按鈕

3.輸入內(nèi)容abc

4.刪除已輸入abc

代碼實(shí)現(xiàn):

# 點(diǎn)擊搜索按鈕driver.find_element_by_id("com.android.settings:id/search").click()# 定位到輸入框并輸入abcinput_text = driver.find_element_by_id("android:id/search_src_text")# 輸入abcinput_text.send_keys("abc")time.sleep(1)# 刪除abcinput_text.clear()

7.4. 獲取元素的文本內(nèi)容

方法: text

業(yè)務(wù)場(chǎng)景:

1.進(jìn)入設(shè)置

2.獲取所有元素class屬性為“android.widget.TextView”的文本內(nèi)容

代碼實(shí)現(xiàn):

ele_list=driver.find_elements_by_class_name("android.widget.TextView")foreinele_list:print(e.text)forindex,iteminenumerate(ele_list):print(index,item.text)

執(zhí)行結(jié)果:

0 設(shè)置? 1? 2 移動(dòng)數(shù)據(jù)網(wǎng)絡(luò)已關(guān)閉? 3 無線和網(wǎng)絡(luò)? 4 WLAN? 5 "guest"? 6 藍(lán)牙? 7 已停用? 8 流量使用情況? 9 已使用 0 B 的數(shù)據(jù)? 10 更多? 11 設(shè)備? 12 顯示? 13 自動(dòng)調(diào)節(jié)亮度功能已關(guān)閉? 14 通知? 15 已允許所有應(yīng)用發(fā)送通知

7.5. 獲取元素的屬性值

方法: get_attribute(value) # value:元素的屬性

?? value='name' 返回content-desc / text屬性值

?? value='text' 返回text的屬性值

?? value='className' 返回 class屬性值弄砍,只有 API=>18 才能支持

?? value='resourceId' 返回 resource-id屬性值,只有 API=>18 才能支持

業(yè)務(wù)場(chǎng)景:

1.進(jìn)入設(shè)置

2.獲取搜索按鈕的content-desc屬性值

代碼實(shí)現(xiàn):

# 定位到搜索按鈕get_value = driver.find_element_by_id("com.android.settings:id/search")print(get_value.get_attribute("content-desc"))執(zhí)行結(jié)果:? ? ? ? 搜索

7.6. 獲取元素在屏幕上的坐標(biāo)

方法:location

業(yè)務(wù)場(chǎng)景:

1.進(jìn)入設(shè)置頁面

2.獲取搜索按鈕在屏幕的坐標(biāo)位置

代碼實(shí)現(xiàn):

# 定位到搜索按鈕get_value = driver.find_element_by_id("com.android.settings:id/search")# 打印搜索按鈕在屏幕上的坐標(biāo)print(get_value.location){'y': 44, 'x': 408}

7.7. 獲取app包名和啟動(dòng)名

獲取包名方法:current_package

獲取啟動(dòng)名:current_activity

業(yè)務(wù)場(chǎng)景:

1.啟動(dòng)設(shè)置

2.獲取包名和啟動(dòng)名

代碼實(shí)現(xiàn):

print(driver.current_package)print(driver.current_activity)

執(zhí)行結(jié)果:

com.tencent.news.activity.SplashActivity

八输涕、APP元素事件操作API

8.1. 前置代碼

fromappiumimportwebdriver# server 啟動(dòng)參數(shù)desired_caps={}# 設(shè)備信息desired_caps['platformName']='Android'desired_caps['platformVersion']='5.1'desired_caps['deviceName']='192.168.56.101:5555'# app的信息desired_caps['appPackage']='com.android.settings'desired_caps['appActivity']='.Settings'# 聲明我們的driver對(duì)象driver=webdriver.Remote('http://127.0.0.1:4723/wd/hub',desired_caps)

8.2. swip滑動(dòng)事件

??從一個(gè)坐標(biāo)位置滑動(dòng)到另一個(gè)坐標(biāo)位置,只能是兩個(gè)點(diǎn)之間的滑動(dòng)

方法:swipe(start_x, start_y, end_x, end_y, duration=None)

參數(shù):

1.start_x:起點(diǎn)X軸坐標(biāo)

2.start_y:起點(diǎn)Y軸坐標(biāo)

3.end_x: 終點(diǎn)X軸坐標(biāo)

4.end_y,: 終點(diǎn)Y軸坐標(biāo)

5.duration: 滑動(dòng)這個(gè)操作一共持續(xù)的時(shí)間長(zhǎng)度音婶,單位:ms

業(yè)務(wù)場(chǎng)景:

1.進(jìn)入設(shè)置

2.從坐標(biāo)(148,659)滑動(dòng)到坐標(biāo)(148,248)

代碼實(shí)現(xiàn):

# 滑動(dòng)沒有持續(xù)時(shí)間driver.swipe(188,659,148,248)# 滑動(dòng)持續(xù)5秒的時(shí)間driver.swipe(188,659,148,248,5000)

8.3. scroll滑動(dòng)事件

?? 從一個(gè)元素滑動(dòng)到另一個(gè)元素,直到頁面自動(dòng)停止

方法:scroll(origin_el, destination_el)

參數(shù):

1.origin_el:滑動(dòng)開始的元素

2.destination_el:滑動(dòng)結(jié)束的元素

業(yè)務(wù)場(chǎng)景:

1.進(jìn)入設(shè)置頁

2.模擬手指從存儲(chǔ)菜單位置 到 WLAN菜單位置的上滑操作

代碼實(shí)現(xiàn):

# 定位到存儲(chǔ)菜單欄el1 = driver.find_element_by_xpath("http://*[contains(@text,'存儲(chǔ)')]")# 定位到WLAN菜單欄el2 = driver.find_element_by_xpath("http://*[contains(@text,'WLAN')]")# 執(zhí)行滑動(dòng)操作driver.scroll(el1,el2)

8.4. drag拖拽事件

?? 從一個(gè)元素滑動(dòng)到另一個(gè)元素,第二個(gè)元素替代第一個(gè)元素原本屏幕上的位置

方法:drag_and_drop(origin_el, destination_el)

參數(shù):

1.origin_el:滑動(dòng)開始的元素

2.destination_el:滑動(dòng)結(jié)束的元素

業(yè)務(wù)場(chǎng)景:

1.進(jìn)入設(shè)置頁

2.模擬手指將存儲(chǔ)菜單 滑動(dòng)到 WLAN菜單欄位置

代碼實(shí)現(xiàn):

# 定位到存儲(chǔ)菜單欄el1 = driver.find_element_by_xpath("http://*[contains(@text,'存儲(chǔ)')]")# 定位到WLAN菜單欄el2 = driver.find_element_by_xpath("http://*[contains(@text,'WLAN')]")# 執(zhí)行滑動(dòng)操作driver.drag_and_drop(el1,el2)

8.5. 應(yīng)用置于后臺(tái)事件

APP放置后臺(tái)莱坎,模擬熱啟動(dòng)

方法:background_app(seconds)

參數(shù):

1.seconds:停留在后臺(tái)的時(shí)間衣式,單位:秒

業(yè)務(wù)場(chǎng)景:

1.進(jìn)入設(shè)置頁

2.將APP置于后臺(tái)5s

代碼實(shí)現(xiàn):

driver.background_app(5)

效果:

app置于后臺(tái)5s后,再次展示當(dāng)前頁面

九檐什、APP模擬手勢(shì)高級(jí)操作

TouchAction是AppiumDriver的輔助類碴卧,主要針對(duì)手勢(shì)操作,比如滑動(dòng)乃正、長(zhǎng)按住册、拖動(dòng)等,原理是將一系列的動(dòng)作放在一個(gè)鏈條中發(fā)送到服務(wù)器瓮具,服務(wù)器接受到該鏈條后荧飞,解析各個(gè)動(dòng)作,逐個(gè)執(zhí)行名党。

9.1. 前置代碼

fromappiumimportwebdriver# server 啟動(dòng)參數(shù)desired_caps={}# 設(shè)備信息desired_caps['platformName']='Android'desired_caps['platformVersion']='5.1'desired_caps['deviceName']='192.168.56.101:5555'# app的信息desired_caps['appPackage']='com.android.settings'desired_caps['appActivity']='.Settings'# 聲明我們的driver對(duì)象driver=webdriver.Remote('http://127.0.0.1:4723/wd/hub',desired_caps)

?? 所有手勢(shì)都要通過執(zhí)行函數(shù)才會(huì)運(yùn)行.

9.2. 手指輕敲操作

模擬手指輕敲一下屏幕操作

方法:tap(element=None, x=None, y=None)

方法:perform() # 發(fā)送命令到服務(wù)器執(zhí)行操作

參數(shù):

1.element:被定位到的元素

2.x:相對(duì)于元素左上角的坐標(biāo)叹阔,通常會(huì)使用元素的X軸坐標(biāo)

3.y:通常會(huì)使用元素的Y軸坐標(biāo)

業(yè)務(wù)場(chǎng)景:

1.進(jìn)入設(shè)置

2.點(diǎn)擊WLAN選項(xiàng)

代碼實(shí)現(xiàn):

# 通過元素定位方式敲擊屏幕el = driver.find_element_by_xpath("http://*[contains(@text,'WLAN')]")TouchAction(driver).tap(el).perform()# 通過坐標(biāo)方式敲擊屏幕,WLAN坐標(biāo):x=155,y=250# TouchAction(driver).tap(x=155,y=250).perform()

9.3. 手指按操作

模擬手指按下屏幕,按就要對(duì)應(yīng)著離開.

方法:press(el=None, x=None, y=None)

方法:release() # 結(jié)束動(dòng)作传睹,手指離開屏幕

參數(shù):

1.element:被定位到的元素

2.x:通常會(huì)使用元素的X軸坐標(biāo)

3.y:通常會(huì)使用元素的Y軸坐標(biāo)

業(yè)務(wù)場(chǎng)景:

1.進(jìn)入設(shè)置

2.點(diǎn)擊WLAN選項(xiàng)

代碼實(shí)現(xiàn):

# 通過元素定位方式按下屏幕el = driver.find_element_by_xpath("http://*[contains(@text,'WLAN')]")TouchAction(driver).press(el).release().perform()# 通過坐標(biāo)方式按下屏幕耳幢,WLAN坐標(biāo):x=155,y=250# TouchAction(driver).press(x=155,y=250).release().perform()

9.4. 等待操作

方法:wait(ms=0)

參數(shù):

ms:暫停的毫秒數(shù)

業(yè)務(wù)場(chǎng)景:

1.進(jìn)入設(shè)置

2.點(diǎn)擊WLAN選項(xiàng)

3.長(zhǎng)按WiredSSID選項(xiàng)5秒

代碼實(shí)現(xiàn):

# 點(diǎn)擊WLANdriver.find_element_by_xpath("http://*[contains(@text,'WLAN')]").click()# 定位到WiredSSIDel =driver.find_element_by_id("android:id/title")# 通過元素定位方式長(zhǎng)按元素TouchAction(driver).press(el).wait(5000).perform()# 通過坐標(biāo)方式模擬長(zhǎng)按元素# 添加等待(有長(zhǎng)按)/不添加等待(無長(zhǎng)按效果)# TouchAction(driver).press(x=770,y=667).wait(5000).release().perform()

9.5. 手指長(zhǎng)按操作

模擬手機(jī)按下屏幕一段時(shí)間,按就要對(duì)應(yīng)著離開.

方法:long_press(el=None, x=None, y=None, duration=1000)

參數(shù):

1.element:被定位到的元素

2.x:通常會(huì)使用元素的X軸坐標(biāo)

3.y:通常會(huì)使用元素的Y軸坐標(biāo)

4.duration:持續(xù)時(shí)間,默認(rèn)為1000ms

業(yè)務(wù)場(chǎng)景:

1.進(jìn)入設(shè)置

2.點(diǎn)擊WLAN選項(xiàng)

3.長(zhǎng)按WiredSSID選項(xiàng)5秒

代碼實(shí)現(xiàn):

# 點(diǎn)擊WLANdriver.find_element_by_xpath("http://*[contains(@text,'WLAN')]").click()# 定位到WiredSSIDel =driver.find_element_by_id("android:id/title")# 通過元素定位方式長(zhǎng)按元素TouchAction(driver).long_press(el,duration=5000).release().perform()# 通過坐標(biāo)方式長(zhǎng)按元素欧啤,WiredSSID坐標(biāo):x=770,y=667# 添加等待(有長(zhǎng)按)/不添加等待(無長(zhǎng)按效果)# TouchAction(driver).long_press(x=770,y=667).perform()

9.6. 手指移動(dòng)操作

模擬手機(jī)的滑動(dòng)操作

方法:move_to(el=None, x=None, y=None)

參數(shù):

1.el:定位的元素

2.x:相對(duì)于前一個(gè)元素的X軸偏移量

3.y:相對(duì)于前一個(gè)元素的Y軸偏移量

業(yè)務(wù)場(chǎng)景1:

1.進(jìn)入設(shè)置

2.向上滑動(dòng)屏幕

代碼實(shí)現(xiàn):

# 定位到存儲(chǔ)el = driver.find_element_by_xpath("http://*[contains(@text,'存儲(chǔ)')]")# 定位到更多el1 = driver.find_element_by_xpath("http://*[contains(@text,'更多')]")# 元素方式滑動(dòng)TouchAction(driver).press(el).move_to(el1).release().perform()# 坐標(biāo)的方式滑動(dòng)# TouchAction(driver).press(x=240,y=600).wait(100).move_to(x=240,y=100).release().perform()# 注意press連接一個(gè)move_to實(shí)際調(diào)用的是swip方法睛藻,可在log中查詢,不要給相對(duì)坐標(biāo)堂油。

業(yè)務(wù)場(chǎng)景2:

1.進(jìn)入設(shè)置

2.向上滑動(dòng)屏幕到可見"安全"選項(xiàng)

3.進(jìn)入到安全

4.點(diǎn)擊屏幕鎖定方式

5.點(diǎn)擊圖案

6.繪制圖案

代碼實(shí)現(xiàn):

# 定位到WLANel1 = driver.find_element_by_xpath("http://*[contains(@text,'WLAN')]")# 定位到存儲(chǔ)el2 = driver.find_element_by_xpath("http://*[contains(@text,'存儲(chǔ)')]")# 存儲(chǔ)上滑到WLANdriver.drag_and_drop(el2,el1)# 定位到用戶el3 = driver.find_element_by_xpath("http://*[contains(@text,'用戶')]")# 注意 這次使用drag_and_drop方法修档,傳入的"存儲(chǔ)定位"仍使用其原始在屏幕上的位置,所以是由存儲(chǔ)滑動(dòng)到用戶才可以上滑府框,否則需要重新"定位存儲(chǔ)"# 存儲(chǔ)上滑倒用戶位置driver.drag_and_drop(el2,el3)# 點(diǎn)擊安全按鈕driver.find_element_by_xpath("http://*[contains(@text,'安全')]").click()# 點(diǎn)擊屏幕鎖定方式按鈕driver.find_element_by_xpath("http://*[contains(@text,'屏幕鎖定')]").click()# 點(diǎn)擊圖案按鈕driver.find_element_by_xpath("http://*[contains(@text,'圖案')]").click()# 繪制圖案四個(gè)坐標(biāo) 1:(244,967) 2:(723,967) 3:(723,1442) 4:(244,1916)TouchAction(driver).press(x=244,y=967).wait(100).move_to(x=479,y=0).wait(100)\? ? ? ? ? .move_to(x=0,y=475).wait(100).move_to(x=-479,y=474).release().perform()

十吱窝、手機(jī)操作API

針對(duì)手機(jī)的一些常用設(shè)置功能進(jìn)行操作.

10.1. 前置代碼

fromappiumimportwebdriver# server 啟動(dòng)參數(shù)desired_caps={}# 設(shè)備信息desired_caps['platformName']='Android'desired_caps['platformVersion']='5.1'desired_caps['deviceName']='192.168.56.101:5555'# app的信息desired_caps['appPackage']='com.android.settings'desired_caps['appActivity']='.Settings'# 聲明我們的driver對(duì)象driver=webdriver.Remote('http://127.0.0.1:4723/wd/hub',desired_caps)

10.2. 獲取手機(jī)時(shí)間

方法:device_time

代碼實(shí)現(xiàn):

# 獲取當(dāng)前手機(jī)的時(shí)間print(driver.device_time)

執(zhí)行結(jié)果:

Wed Dec 27 08:52:45 EST 2017

10.3. 獲取手機(jī)的寬高

獲取手機(jī)的寬高,可以根據(jù)寬高做一些坐標(biāo)的操作

方法:get_window_size()

代碼實(shí)現(xiàn):

print(driver.get_window_size())

執(zhí)行結(jié)果:

{'height': 800, 'width': 480}

10.4. 發(fā)送鍵到設(shè)備

模擬系統(tǒng)鍵值的操作迫靖,比如操作home鍵院峡,音量鍵,返回鍵等。

參數(shù):

keycode:發(fā)送給設(shè)備的關(guān)鍵代碼

metastate:關(guān)于被發(fā)送的關(guān)鍵代碼的元信息系宜,一般為默認(rèn)值

業(yè)務(wù)場(chǎng)景:

1.打開設(shè)置

2.按多次音量增加鍵

代碼實(shí)現(xiàn):

for i inrange(3):driver.keyevent(24)

Appium---Android的keycode鍵值

adb命令使用

adb shell input keyevent XX(EventCode) #輸入對(duì)應(yīng)的鍵值

adb shell input text "www.baidu.com"

?#向?yàn)g覽器發(fā)送文本

EventCodeKeyEventEventName

0KEYCODE_UNKNOWN未知鍵

1KEYCODE_SOFT_LEFT左鍵

2KEYCODE_SOFT_RIGHT右鍵

3KEYCODE_HOMEHome鍵

4KEYCODE_BACK返回鍵

5KEYCODE_CALL撥號(hào)鍵

6KEYCODE_ENDCALL掛機(jī)鍵

7KEYCODE_0按鍵“0”

8KEYCODE_1按鍵“1”

9KEYCODE_2按鍵“2”

10KEYCODE_3按鍵“3”

11KEYCODE_4按鍵“4”

12KEYCODE_5按鍵“5”

13KEYCODE_6按鍵“6”

14KEYCODE_7按鍵“7”

15KEYCODE_8按鍵“8”

16KEYCODE_9按鍵“9”

17KEYCODE_STAR按鍵“*”

18KEYCODE_POUND按鍵“#”

19KEYCODE_DPAD_UP導(dǎo)航鍵 向上

20KEYCODE_DPAD_DOWN導(dǎo)航鍵 向下

21KEYCODE_DPAD_LEFT導(dǎo)航鍵 向左

22KEYCODE_DPAD_RIGHT導(dǎo)航鍵 向右

23KEYCODE_DPAD_CENTER導(dǎo)航鍵 確定

24KEYCODE_VOLUME_UP音量鍵加

25KEYCODE_VOLUME_DOWN音量鍵減

26KEYCODE_POWER電源鍵

27KEYCODE_CAMERA相機(jī)鍵

28KEYCODE_CLEAR清除鍵

29KEYCODE_A按鍵“A”

30KEYCODE_B按鍵“B”

31KEYCODE_C按鍵“C”

32KEYCODE_D按鍵“D”

33KEYCODE_E按鍵“E”

34KEYCODE_F按鍵“F”

35KEYCODE_G按鍵“G”

36KEYCODE_H按鍵“H”

37KEYCODE_I按鍵“I”

38KEYCODE_J按鍵“J”

39KEYCODE_K按鍵“K”

40KEYCODE_L按鍵“L”

41KEYCODE_M按鍵“M”

42KEYCODE_N按鍵“N”

43KEYCODE_O按鍵“O”

44KEYCODE_P按鍵“P”

45KEYCODE_Q按鍵“Q”

46KEYCODE_R按鍵“R”

47KEYCODE_S按鍵“S”

48KEYCODE_T按鍵“T”

49KEYCODE_U按鍵“U”

50KEYCODE_V按鍵“V”

51KEYCODE_W按鍵“W”

52KEYCODE_X按鍵“X”

53KEYCODE_Y按鍵“Y”

54KEYCODE_Z按鍵“Z”

55KEYCODE_COMMA按鍵“,”

56KEYCODE_PERIOD按鍵‘.’

57KEYCODE_ALT_LEFT組合鍵 Alt+Left

58KEYCODE_ALT_RIGHT組合鍵 Alt+Right

59KEYCODE_SHIFT_LEFT組合鍵 Shift+Left

60KEYCODE_SHIFT_RIGHT組合鍵 Shift+Left

61KEYCODE_TABTab鍵

62KEYCODE_SPACE空格鍵

63KEYCODE_SYM選擇輸入法

64KEYCODE_EXPLORER瀏覽器

65KEYCODE_ENVELOPE郵件

66KEYCODE_ENTER回車鍵

67KEYCODE_DEL退格鍵

68KEYCODE_GRAVE按鍵‘`’

69KEYCODE_MINUS按鍵‘-’

70KEYCODE_EQUALS按鍵‘=’

71KEYCODE_LEFT_BRACKET按鍵‘[’

72KEYCODE_RIGHT_BRACKET按鍵‘]’

73KEYCODE_BACKSLASH按鍵‘\’

74KEYCODE_SEMICOLON按鍵‘,’

75KEYCODE_APOSTROPHE按鍵‘'’(單引號(hào))

76KEYCODE_SLASH按鍵‘/’

77KEYCODE_AT按鍵‘@’

78KEYCODE_NUM按鍵Number modifier

79KEYCODE_HEADSETHOOK按鍵Headset Hook

80KEYCODE_FOCUS拍照對(duì)焦鍵

81KEYCODE_PLUS按鍵‘+’

82KEYCODE_MENU菜單鍵

83KEYCODE_NOTIFICATION通知鍵

84KEYCODE_SEARCH搜索鍵

85TAG_LAST_KEYCODE

10.5. 操作手機(jī)通知欄

打開手機(jī)的通知欄照激,可以獲取通知欄的相關(guān)信息和元素操作

方法:open_notifications()

業(yè)務(wù)場(chǎng)景:

1.啟動(dòng)設(shè)置

2.打開通知欄

代碼實(shí)現(xiàn):

driver.open_notifications()

10.6. 獲取手機(jī)當(dāng)前網(wǎng)絡(luò)

獲取手機(jī)當(dāng)前連接的網(wǎng)絡(luò)

方法:network_connection

業(yè)務(wù)場(chǎng)景:獲取手機(jī)當(dāng)前網(wǎng)絡(luò)模式

代碼實(shí)現(xiàn):

print(driver.network_connection)

執(zhí)行結(jié)果:

6

Value (Alias)DataWifiAirplane Mode

0 (None)000

1 (Airplane Mode)001

2 (Wifi only)010

4 (Data only)100

6 (All network on)110

10.7. 設(shè)置手機(jī)網(wǎng)絡(luò)

更改手機(jī)的網(wǎng)絡(luò)模式,模擬特殊網(wǎng)絡(luò)情況下的測(cè)試用例

方法:set_network_connection(connectionType)

參數(shù):

connectionType:需要被設(shè)置成為的網(wǎng)絡(luò)類型

業(yè)務(wù)場(chǎng)景:

1.啟動(dòng)設(shè)置

2.設(shè)置手機(jī)網(wǎng)絡(luò)為飛行模式

代碼實(shí)現(xiàn):

driver.set_network_connection(1)

10.8. 手機(jī)截圖

截取手機(jī)當(dāng)前屏幕盹牧,保存指定格式圖片到設(shè)定位置

方法:get_screenshot_as_file(filename)

參數(shù):

filename:指定路徑下俩垃,指定格式的圖片.

業(yè)務(wù)場(chǎng)景:

1.打開設(shè)置頁面

2.截圖當(dāng)前頁面保存到當(dāng)前目錄励幼,命名為screen.png

代碼實(shí)現(xiàn):

importosdriver.get_screenshot_as_file(os.getcwd()+os.sep+'./screen.png')

執(zhí)行結(jié)果:

當(dāng)前目錄下會(huì)生成screen.png文件

十一、腳本錄制

11.1. 認(rèn)識(shí)界面

image.png

11.2. 點(diǎn)擊開始錄制按鍵開始錄制腳本

點(diǎn)擊頂部導(dǎo)航欄左側(cè)第一個(gè)“選擇元素”按鍵選定搜索欄口柳,然后點(diǎn)擊右邊點(diǎn)“點(diǎn)擊”按鍵進(jìn)行操作(錄制過程就是先選擇錄制窗口左邊的APP元素苹粟,然后錄制窗口右邊的操作方式)。

錄制完成后點(diǎn)擊“停止錄制”按鍵跃闹,錄制窗口右上角會(huì)同步顯示操作代碼嵌削,選擇代碼類型,將模板代碼轉(zhuǎn)換成正式代碼望艺,復(fù)制代碼到Pycharm苛秕。

代碼復(fù)制到pycharm后,最好是在每個(gè)操作或者頁面切換處加上等待時(shí)間找默,否則會(huì)因?yàn)榫W(wǎng)速艇劫、APP設(shè)計(jì)問題或者其他原因,無法及時(shí)到達(dá)下一個(gè)頁面啡莉,導(dǎo)致APPIUM無法獲取頁面元素而定位元素失敗港准,在pycharm運(yùn)行時(shí)報(bào)錯(cuò)。代碼編輯好后點(diǎn)擊pycharm的運(yùn)行按鍵咧欣,APPium就會(huì)在手機(jī)上面自動(dòng)運(yùn)行腳本了浅缸。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市魄咕,隨后出現(xiàn)的幾起案子衩椒,更是在濱河造成了極大的恐慌,老刑警劉巖哮兰,帶你破解...
    沈念sama閱讀 221,820評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件毛萌,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡喝滞,警方通過查閱死者的電腦和手機(jī)阁将,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來右遭,“玉大人做盅,你說我怎么就攤上這事【焦” “怎么了吹榴?”我有些...
    開封第一講書人閱讀 168,324評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)滚婉。 經(jīng)常有香客問我图筹,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,714評(píng)論 1 297
  • 正文 為了忘掉前任远剩,我火速辦了婚禮扣溺,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘民宿。我一直安慰自己娇妓,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評(píng)論 6 397
  • 文/花漫 我一把揭開白布活鹰。 她就那樣靜靜地躺著,像睡著了一般只估。 火紅的嫁衣襯著肌膚如雪志群。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,328評(píng)論 1 310
  • 那天蛔钙,我揣著相機(jī)與錄音锌云,去河邊找鬼。 笑死吁脱,一個(gè)胖子當(dāng)著我的面吹牛桑涎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播兼贡,決...
    沈念sama閱讀 40,897評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼攻冷,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了遍希?” 一聲冷哼從身側(cè)響起等曼,我...
    開封第一講書人閱讀 39,804評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎凿蒜,沒想到半個(gè)月后禁谦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,345評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡废封,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評(píng)論 3 340
  • 正文 我和宋清朗相戀三年州泊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片漂洋。...
    茶點(diǎn)故事閱讀 40,561評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡遥皂,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出氮发,到底是詐尸還是另有隱情渴肉,我是刑警寧澤,帶...
    沈念sama閱讀 36,238評(píng)論 5 350
  • 正文 年R本政府宣布爽冕,位于F島的核電站仇祭,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏颈畸。R本人自食惡果不足惜乌奇,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評(píng)論 3 334
  • 文/蒙蒙 一没讲、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧礁苗,春花似錦爬凑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至疏叨,卻和暖如春潘靖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蚤蔓。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工卦溢, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人秀又。 一個(gè)月前我還...
    沈念sama閱讀 48,983評(píng)論 3 376
  • 正文 我出身青樓单寂,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親吐辙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子宣决,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容