日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

从头到脚说单测——谈有效的单元测试

發布時間:2024/2/28 编程问答 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从头到脚说单测——谈有效的单元测试 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

導語?非常幸運的是,從4月份至今,我能夠全身心投入到騰訊新聞的單元測試專項任務中,從無知懵懂,到不斷深入理解的過程,與開發同學互幫互助,受益匪淺。在此過程中,得到了質量總監、新聞總監和喬幫主的傾囊指導,真心感謝!!我希望把所有心得,總結成一篇較為全面的文章,分享給其他團隊。時刻牢記:1. 不要濫用mock 2. 基于意圖。

在我們談到單元測試,大都清楚是測試函數符合預期,國外很多大公司都將單測執行的很好,國內成功的案例則相對有限。在本文中,筆者將在騰訊新聞項目中親身經歷單測從無到有的實踐過程梳理為可讀可參考的經驗分享出來。在實踐的過程我發現,單測可以推動產品質量轉為優秀,推動實行它的過程更需要對它有真實的認識以及一套方法論。


為單元測試“正名”

我曾經認為,單元測試面向的是一個函數。任何走出一個函數的測試,都不是單元測試。


其實,對“單元”的定義取決于自己。如果你正在使用函數式編程,一個單元最有可能指的是一個函數。你的單元測試將使用不同的參數調用這個函數,并斷言它返回了期待的結果;在面向對象語言里,下至一個方法,上至一個類都可以是一個單元(從一個單一的方法到一整個的類都可以是一個單元)。意圖很重要(“意圖”二字是本文中第一次提到,它很重要)


我們有單元測試、增量測試、集成測試、回歸測試、冒煙測試等等,名字非常多。谷歌看到這種“百家爭鳴”的現象,創立了自己的命名方式,只分為小型測試、中型測試大型測試

  • 小型測試,針對單個函數的測試,關注其內部邏輯,mock所有需要的服務。小型測試帶來優秀的代碼質量、良好的異常處理、優雅的錯誤報告

  • 中型測試,驗證兩個或多個制定的模塊應用之間的交互

  • 大型測試,也被稱為“系統測試”或“端到端測試”。大型測試在一個較高層次上運行,驗證系統作為一個整體是如何工作的。

資源

小型測試

中型測試

大型測試

網絡訪問

僅訪問localhost

數據庫訪問

訪問文件

訪問用戶界面

使用外部服務

不鼓勵,可mock

多線程

使用sleep語句

使用系統屬性設置

運行時間限制(毫秒)

60

300

900+

強制時間限制(分鐘)

1

5

15


小型測試

中型測試

大型測試

對應測試類型

單元測試

單元測試+邏輯層測試(泛單元或分層測試)

UI測試或接口測試

結論:我們的單元測試,既可以針對一個函數寫case,也可以按照函數的調用關系串起來寫case。


金字塔模型

在金字塔模型之前,流行的是冰淇淋模型。包含了大量的手工測試、端到端的自動化測試及少量的單元測試。造成的后果是,隨著產品壯大,手工回歸測試時間越來越長,質量很難把控;自動化case頻頻失敗,每一個失敗對應著一個長長的函數調用,到底哪里出了問題?單元測試少的可憐,基本沒作用。

Mike Cohn 在他的著作《Succeeding with Agile》一書中提出了“測試金字塔”這個概念。這個比喻非常形象,它讓你一眼就知道測試是需要分層的。它還告訴你每一層需要寫多少測試。


測試金字塔本身是一條很好的經驗法則,我們最好記住Cohn在金字塔模型中提到的兩件事:

  • 編寫不同粒度的測試

  • 層次越高,你寫的測試應該越少

同時,我們對金字塔的理解絕不能止步于此,要進一步理解:


我把金字塔模型理解為——冰激凌融化了。就是指,最頂部的“手工測試”理論上全部要自動化,向下融化,優先全部考慮融化成單元測試,單元測試覆蓋不了的 放在中間層(分層測試),再覆蓋不了的才會放到UI層。因此,UI層的case,能沒有就不要有,跑的慢還不穩定。按照喬幫主的說法,我不分單元測試還是分層測試,統一都叫自動化測試,那就應該把所有的自動化case看做一個整體,case不要冗余,單元測試能覆蓋,就要把這個case從分層或ui中去掉。


越是底層的測試,牽扯到相關內容越少,而高層測試則涉及面更廣。比如單元測試,它的關注點只有一個單元,而沒有其它任何東西。所以,只要一個單元寫好了,測試就是可以通過的;而集成測試則要把好幾個單元組裝到一起才能測試,測試通過的前提條件是,所有這些單元都寫好了,這個周期就明顯比單元測試要長;系統測試則要把整個系統的各個模塊都連在一起,各種數據都準備好,才可能通過。


另外,因為涉及到的模塊過多,任何一個模塊做了調整,都有可能破壞高層測試,所以,高層測試通常是相對比較脆弱的,在實際的工作中,有些高層測試會牽扯到外部系統,這樣一來,復雜度又在不斷地提升。


為什么做單測

這個問題我們規避不掉。新聞是這次研發模式改革的主力軍之一,所以自上而下的推動讓這個問題不那么棘手:做了就是做了。不做,卻又有那么多的理由:(搜集到的吐槽真實聲音)

  • 單元測試浪費了太多的時間

  • 單元測試僅僅是證明這些代碼做了什么

  • 我是很棒的程序員,我是不是可以不進行單元測試?

  • 后面的集成測試將會抓住所有的bug

  • 單元測試的成本效率不高我把測試都寫了,那么測試人員做什么呢?

  • 公司請我來是寫代碼,而不是寫測試

  • 測試代碼的正確性,并不是我的工作

我覺得我們總監指導的很到位:改革,一是工作方式的改革,更難的是思想上的改革。


單元測試的意義

新聞的總監dot老師是至始至終推進單測的好領導,他講述了螺絲釘與飛機的故事:干貨 | 測試扁平化之必備神器:好的單元測試

  • 單元測試對我們的產品質量是非常重要的。

  • 單元測試是所有測試中最底層的一類測試,是第一個環節,也是最重要的一個環節,是唯一一次有保證能夠代碼覆蓋率達到100%的測試,是整個軟件測試過程的基礎和前提,單元測試防止了開發的后期因bug過多而失控,單元測試的性價比是最好的。

  • 據統計,大約有80%的錯誤是在軟件設計階段引入的,并且修正一個軟件錯誤所需的費用將隨著軟件生命期的進展而上升。錯誤發現的越晚,修復它的費用就越高,而且呈指數增長的趨勢。作為編碼人員,也是單元測試的主要執行者,是唯一能夠做到生產出無缺陷程序這一點的人,其他任何人都無法做到這一點

  • 代碼規范、優化,可測試性的代碼

  • 放心重構

  • 自動化執行three-thousand times

下面這張圖,來自微軟的統計數據:bug在單元測試階段被發現,平均耗時3.25小時,如果漏到系統測試階段,要花費11.5小時。

下面這張圖,旨在說明兩個問題:85%的缺陷都在代碼設計階段產生,而發現bug的階段越靠后,耗費成本就越高,指數級別的增高。所以,在早期的單元測試就能發現bug,省時省力,一勞永逸,何樂而不為呢


單元測試特別耗時?

不能一刀切,不能只盯著單測階段的耗時。


我采訪了新聞客戶端、后臺的開發,首先肯定的是,單測會增加開發量、增加開發時長。

在《單元測試的藝術》這本書提到一個案例:找了開發能力相近的兩個團隊,同時開發相近的需求。進行單測的團隊在編碼階段時長增長了一倍,從7天到14天,但是,這個團隊在集成測試階段的表現非常順暢,bug量小,定位bug迅速等。最終的效果,整體交付時間和缺陷數,均是單測團隊最少。


單測,存在即合理。一方面,需要把單測放在整個迭代周期來觀測其效果;一方面,寫單測也是技術活,寫得好的同學,時間少代碼質量高(也即,不是說寫了單測,就能寫好單測)


誰來寫單測呢?

  • 開發同學寫單測

  • 測試同學具有寫單測的能力。重點在于開發腳手架、分層測試/端到端測試


增量還是存量

  • 單測case針對增量代碼

  • 當存量代碼出現大規模重構,后者質量暴露出極大風險時,都是推動補全單測的好時機


單元測試的階段

一. 廣義的單元測試,我們指這三部分的有機組合:

  • code review

  • 靜態代碼掃描

  • 單元測試用例編寫

二. 結合新聞的實踐,我把單測成長的過程分為4個目標,分別為:

  • 會寫,全員可寫

  • 寫的好,同時關注可測性問題,試點解決

  • 識別可測性問題,熟練使用重構方法進行重構;識別代碼架構設計問題;case與業務代碼同步編寫

  • TDD。但這個目標是期望,不能作為必須實現的目標。

截至發稿當天,新聞處于第三階段,即,每個迭代均能產出高質量的case,人數覆蓋和需求覆蓋均較高;關注重點在于可測性,時刻注重重構。


單元測試的指標

還挺尷尬的,不太有直接的指標去衡量單測的效果。我們也經常被問到,“怎么證明你們新聞單測的作用呀?”

  • bug類指標(間接指標):連續迭代的bug總數趨勢、迭代內新建bug的趨勢、千行bug率

  • 單測的需求覆蓋度(50%以上),參與人員覆蓋度(80%以上)

  • 單測case總數趨勢,代碼行增量趨勢

  • 增量代碼的行覆蓋率(接入層80%,客戶端30%)

  • 單函數圈復雜度(低于40),單函數代碼行數(低于80),掃描告警數


在迭代需求持續高吞吐量的前提下,以新聞iOS的數據為例:

go單元測試框架選型

基本選型:testify + gomonkey

附加:httptest + sqlmock


前提

  • 測試文件,以_test.go結尾,與被測文件放于相同目錄

  • 測試函數,函數名以Test開頭,并且隨后的第一個字符必須為大寫字母或下劃線,如:TestParseReq_CorrectNum_TableDriven

  • 測試函數,參數為t *testing.T;對于bench測試,參數為b *testing.B

  • 運行命令行,我的文章有深入講解:go test命令行


testify常規用法

https://github.com/stretchr/testify

testify基于gotesting編寫,所以語法上、執行命令行與go test完全兼容

  • 支持大量高效的api,比如:

??? assert.Equal:常規對比,是把兩者分別換成[]byte去嚴格比對

??? assert.Nil:判斷對象為nil時,有時對err判空時也用

??? assert.Error:判斷err的具體類型和內容

??? assert.JSONEq:這個比較有用,對比map時;或者對比struct的時候,也會先轉為map,在用這個api去做對比,如下面這個例子,我封裝了建議的方法去將struct轉換為string(json):

  • 支持suite,用例集管理

  • 運行時,可以指定用例集執行

  • 自帶mock工具,但只支持接口方法的mock,而且用法相對復雜

  • table-driven


gomonkey用法(加粗字體表示常用)

https://github.com/agiledragon/gomonkey

https://studygolang.com/articles/15034

  • 支持為一個函數打一個樁

  • 支持為一個成員方法打一個樁


  • 支持為一個全局變量打一個樁

  • 支持為一個函數變量打一個樁

  • 支持為一個函數打一個特定的樁序列

  • 支持為一個成員方法打一個特定的樁序列


  • 支持為一個函數變量打一個特定的樁序列

  • table-driven的方式定義一系列stub

注意,對內聯函數的Stub,go test命令行一定要加上參數才可生效。見官方文檔。所以,我的命令行默認加上-gcflags=all=-l就行了。

我設置了一些goland的代碼模板,放在附件中。


ApplyFunc是對外部函數Stub(非類方法)

/* 用法:gomonkey.ApplyFunc(被stub函數名, 被stub函數簽名) 函數返回值 *例子: patches := gomonkey.ApplyFunc(fake.Exec, func(_ string, _ ...string) (string, error) { return outputExpect, nil }) */ patches := gomonkey.ApplyFunc(lcache.GetCache, func(_ string) (interface{}, bool) { return getCommentsResp() }) defer patches.Reset()

(左滑可查看完整代碼,下同)


ApplyMethod是對類函數Stub。但這里注意,要被stub的方式是私有方法,gomonkey通過反射是找不到的,有兩種解決方法:

1)使用增強版的gomonkey;

2)不Stub它,而是選擇走進這個函數,這個話題在后面專題談mock的時候說。

/* 用法:gomonkey.ApplyMethod(反射類名, 被stub函數簽名) 函數返回值 *例子: var s *fake.Slice patches := ApplyMethod(reflect.TypeOf(s), "Add", func(_ *fake.Slice, _ int) error { return nil }) */ var ac *auth.AuthCheck patches := gomonkey.ApplyMethod(reflect.TypeOf(ac), "PrepareWithHttp", func(_ *auth.AuthCheck, _ *http.Request, _ ...auth.AuthOption) error { return fmt.Errorf("prepare with nil object") }) defer patches.Reset()

ApplyMethodSeq是對同一個Stub的函數返回不同的結果

/* 用法:gomonkey.ApplyMethodSeq(類的反射,"被stub函數名", 返回結構體); Params{info1},中括號內為被stub函數的返回值列表; Times為生效次數 *例子: e := &fake.Etcd{} info1 := "hello cpp" info2 := "hello golang" info3 := "hello gomonkey" outputs := []OutputCell{ {Values: Params{info1, nil}}, {Values: Params{info2, nil}}, {Values: Params{info3, nil}}, } patches := ApplyMethodSeq(reflect.TypeOf(e), "Retrieve", outputs) defer patches.Reset() */ conn := &redis.RedisConn{} patch1 := gomonkey.ApplyFunc(redis.NewRedisHTTP, func(serviceName string, _ string) *redis.RedisConn { conn := &redis.RedisConn{ redis.RedisConfig{}, &redis.RedisHelper{}, } return conn }) defer patch1.Reset() // mock redis data. 返回空和不為空的情況 outputCell := []gomonkey.OutputCell{ {Values: gomonkey.Params{"12", nil}, Times: 1}, {Values: gomonkey.Params{"", nil}, Times: 1}, } patchs := gomonkey.ApplyMethodSeq(reflect.TypeOf(conn.RedisHelper), "Get", outputCell) defer patchs.Reset()

先舉這幾個例子,詳細的可以在上面的鏈接文章中全面得到。


這里補充一點,對類方法進行stub,必須要找到該方法對應的真實的類(結構體),舉個例子:

//被測函數中有如下一段,其中的Get方法我們想stub掉,只要找到Get方法對應的類就好了 readCountStr, _ := conn.Get(redisKey) if len(readCountStr) == 0 { return 0, nil }

定位conn,是RedisConn類型的struct type RedisConn struct { RedisConfig *RedisHelper } 所以第一次,我用gomonkey.AppleyMethod時這么寫: patches := gomonkey.ApplyMethod(reflect.TypeOf(*RedisConn),"Get", func(_ *redis.RedisHelper,_ string, _ []string) ([]string, error){ return info,err_notNil }) defer?patches.Reset()

運行時報了空指針panic,提示RedisConn沒有Get方法。


繼續追,原來Get是*RedisHelper的方法,組合到了RedisConn結構體中,共用方法。但我們使用gomonkey時,需要指向真正定義它的類

func (this *RedisHelper) Get(key string) (string, error) { return redigo.String(this.Do("GET", key))

最終這么寫:

patches := gomonkey.ApplyMethod(reflect.TypeOf(giftData.rankRedisRD.RedisHelper),"Get", func(_ *redis.RedisHelper,_ string, _ []string) ([]string, error){ return info,err_notNil }) defer patches.Reset()

必須說一說mock了

test doubles

在《xUnit Test Patterns》一書中,作者首次提出test doubles(測試替身)的概念。我們常掛在嘴邊的mock只是其中一種,而且是最容易與Stub(打樁)混淆的一種。在上一節中對gomonkey的介紹,你可以注意到了,我沒有使用mock,全部是Stub。是的,gomonkey不是mock工具,只是一個高級打樁的工具,適配了我們大部分的使用場景。


測試替身,共有五種:可以參考這篇翻譯《xUnit Test Patterns》學習筆記6 - Test Double

  • Dummy Object:

????用于傳遞給調用者但是永遠不會被真實使用的對象,通常它們只是用來填滿參數列表


  • Test Stub

??? Stubs通常用于在測試中提供封裝好的響應,譬如有時候編程設定的并不會對所有的調用都進行響應。Stubs也會記錄下調用的記錄,譬如一個email gateway就是一個很好的例子,它可以用來記錄所有發送的信息或者它發送的信息的數目。簡而言之,Stubs一般是對一個真實對象的封裝


  • Test Spy

??? Test Spy像一個間諜,安插在了SUT內部,專門負責將SUT內部的間接輸出(indirect outputs)傳到外部。它的特點是將內部的間接輸出返回給測試案例,由測試案例進行驗證,Test Spy只負責獲取內部情報,并把情報發出去,不負責驗證情報的正確性


  • Mock Object

????針對設定好的調用方法與需要響應的參數封裝出合適的對象


  • Fake Object

??? Fake對象常常與類的實現一起起作用,但是只是為了讓其他程序能夠正常運行,譬如內存數據庫就是一個很好的例子。


stub與mock

打樁和mock應該是最容易混淆的,而且習慣上我們統一用mock去形容模擬返回的能力,習慣成自然,也就把mock常掛在嘴邊了。


就我的理解,stub可以理解為mock的子集,mock更強大一些:

  • mock可以驗證實現過程,驗證某個函數是否被執行,被執行幾次

  • mock可以依條件生效,比如傳入特定參數,才會使mock效果生效

  • mock可以指定返回結果

  • 當mock指定任何參數都返回固定的結果時,它等于stub

只不過,go的mock工具gomock只基于接口生效,不適合新聞、企鵝號項目,而gomonkey的stub覆蓋了大部分的使用場景。


不要濫用mock

我把這一部分單獨放一章節,表現出它重要的意義。需要讀懂肖鵬的《mock七宗罪》,在gitchat上。


兩個門派

約從2004-2005年間,江湖上形成兩大門派:經典測試驅動開發派 和 mockist(mock極端派)。


先說mockist。他主張將被測函數?所有?調用的外面函數,全部mock。也即,只關注被測函數自己的一行行代碼,只要調用其他函數,全都mock掉,用假數據來測試。


再說經典測試驅動開發派,他們主張不要濫用mock,能不mock就不mock,被測單元也不一定是具體的一個函數,可能是多個函數,串起來。必要的時候再mock。


兩個門派相爭多年,理論各有利弊,至今仍然共存。存在即合理。比如mockist,使用了過多的mock,無法覆蓋函數接口,這部分又是很容易出錯的;經典派,串的太多,又被質疑是集成測試。


對于我們實際應用,不必強制遵從某一派,結合即可,需要的時候mock,盡量少mock,不用糾結。


什么時候適合mock

如果一個對象具有以下特征,比較適合使用mock對象:

  • 該對象提供非確定的結果(比如當前的時間或者當前的溫度)

  • 對象的某些狀態難以創建或者重現(比如網絡錯誤或者文件讀寫錯誤)

  • 對象方法上的執行太慢(比如在測試開始之前初始化數據庫)

  • 該對象還不存在或者其行為可能發生變化(比如測試驅動開發中驅動創建新的類)

  • 該對象必須包含一些專門為測試準備的數據或者方法(后者不適用于靜態類型的語言,流行的Mock框架不能為對象添加新的方法。Stub是可以的。)

因此,不要濫用mock(stub),當被測方法中調用其他方法函數,第一反應應該走進去串起來,而不是從根部就mock掉了。


用例設計法

喬幫主介紹了一篇文章:像機器一樣思考

文章講述思考程序設計的根本思路——考慮輸入輸出。我們設計case,想要得到最全面的設計,根本是考慮全輸入全輸出的組合,當然,一方面,這么做耗時太大,很多時候是不可執行的;一方面,這不是想要的結果,要考慮投入產出比。這時,需要理論與實踐相結合,理論指導實踐,實踐精細理論。


先說理論

1. 還是從上篇文章說起,考慮輸入、輸出,就要先知道哪些屬于輸入輸出:

2. 白盒&黑盒設計

白盒法:

  • 邏輯覆蓋(語句、分支、條件、條件組合等)

  • 路徑(全路徑、最小線性無關路徑)

  • 循環:結合5種場景(跳過循環、循環一次,循環最大次,循環m次命中、循環m次未命中)

黑盒法:

等價類:正確的,錯誤的(合法的,非法的)

邊界法:[1,10] ==> 0,1,2,9,10,11(是等價類的有效補充)

3. 結合應用

全輸入輸出,實施難度較大,轉而我們思考到業內大神們設計出白盒黑盒設計法,通過仔細思考,可以判斷出是對全輸入全輸出的方法論體現。


因此,白盒&黑盒用例設計法,每一種我都親自實踐,理解其優缺點,從設計覆蓋角度,條件組合>最小線性無關路徑>條件>分支>語句。


下面這張圖,是我早期思考用例設計時的一次實踐,現在回憶起來,它過度設計了。

但實際中,我們擔心“過度設計”,也還無法給出答案“用什么方法設計保證萬無一失”。

  • 過度設計,也會使case脆弱

  • 在有限的時間內,我們尋求收益較大化


1. 小函數&重要(計算,對象處理):盡量設計全面


2. 邏輯較重,代碼行數較多:分支、語句覆蓋 + 循環 + 典型的邊界處理(我們看個例子:GetUserGiftList)


3. 引出“基于實現”與“基于意圖”的設計:過多去Stub被測函數內部的調用,就越接近“基于實現”(第二次提到“基于意圖”)


基于意圖與基于實現

這個話題是非常重要的。


基于意圖:思考函數最終想做什么,把被測函數當做黑盒,考慮其輸出輸出,而不要關注其中間是怎樣實現的,究竟生成了什么臨時變量,循環了幾次,有什么判斷等。


基于實現:輸入輸出我也考慮,中間怎么實現的我也考慮。mock就是一個好例子,比如我們寫一個case,我們會用mock去驗證函數內是否調用了哪個外部方法、調用了幾次,語句的執行順序是怎樣的。程序的變動比需求還快,重構隨時都有,稍有一變,case大批量失敗,這也是《mock七宗罪》中提到的一種情況。


我們要的是基于意圖,遠離基于實現。


dot老師和喬幫主給我們上了課程,結合實戰經驗,我總結如下:

  • “要么寫好,要么不寫”。case也是代碼,也需要維護,也有工作量,所以要寫的到位,而不是寫得多。寫了一堆沒用的,你還得維護,不如刪了。

  • 拿到一個函數,先問問自己,這個函數要實現什么功能,最終輸出是什么;然后,問自己,這個函數的風險在哪里,哪部分邏輯不太自信,最容易出錯(計算、復雜的判斷、某異常分支的命中等)。這些才是我們case要覆蓋的點。

  • 內聯函數、直接get/set,沒幾行沒什么邏輯的,只要你判斷沒什么風險,就不用寫case。


  • 確定了要寫的case,再用分支條件組合、邊界等核心方面設計出具體用例,實施編寫。

  • 可以結合新聞幾次單測case review記錄,來詳細理解。詳見我的KM文章

    我們看一個具體的case:

  • 拿到這個函數,作為測試同學的我先向開發了解該函數的意圖:對符合格式、符合時間的用戶禮物進行加和

  • 讀代碼,了解了代碼流程、幾個異常分支,先做了code review

  • 根據必要的異常分支,設計case覆蓋

  • 對正常的業務流程,是按照開發講述的函數意圖,進行設計,case如下:

  • 被測函數:?

    ret := make(map[int]int) now := library.UnixNow() for record, numStr := range giftRecord { hasNum, err := strconv.Atoi(numStr) if err != nil || hasNum < 0 { continue } detail := strings.Split(record, ":") if len(detail) != 2 { continue } itemExpire, err := strconv.ParseInt(detail[1], 10, 64) if err != nil { continue } //星星過期 if itemExpire != 0 && now > itemExpire { continue } //統計可用數目 giftId, err := strconv.Atoi(detail[0]) if err != nil { continue } if _, ok := ret[giftId]; !ok { ret[giftId] = hasNum } else { ret[giftId] += hasNum } }

    正常路徑的單測case

    func TestNum_CorrectRet(t *testing.T) { giftRecord := map[string]string{ "1:1000": "10", "1:2001": "100", "1:999": "20", "2": "200", "a": "30", "2:1001": "20", "2:999": "200", } expectRet := map[int]int{ 1: 110, 2: 20, } var s *redis.xxx patches := gomonkey.ApplyMethod(reflect.TypeOf(s), "Getxxx", func(_ *redis.xxx, _ string)(map[string]string, error) { return giftRecord, nil }) defer?patches.Reset() p := &StarData{xxx } userStarNum,?err?:=?p.GetNum(10000) assert.Nil(t, err) assert.JSONEq(t,?Calorie.StructToString(expectRet),?Calorie.StructToString(userStarNum)) }

    有同學會問到:但是你最終還是看的代碼呀?看到代碼的正確邏輯是怎么處理的,再去設計的case和構造數據吧?而且你不看代碼,怎么知道有哪些異常分支要覆蓋呢?


    答:1. 我現在作為測試同學寫開發同學的case,確實需要知道有哪些異常分支要處理, 但不局限于代碼中的幾種,還應該包括我理解到的異常分支,都要體現在case中。我們的case絕不是為了證明代碼是怎么實現的!通過單測,我們經常能夠發現bug。但是將來是開發來寫單測的,他自己設計的函數肯定知道要覆蓋哪些異常分支。


    2. 嗯,我需要看代碼的正常流程是怎樣的,但不代表著把代碼扒下來以設計出case。case實際上是通過與開發的溝通后,了解輸入數據的結構,輸出的格式,數據校驗和計算的過程,去設計輸入輸出的。


    用例編寫的策略

    對于怎么個順序去寫單測,我們重點實踐了一番,基本上也就三種情況吧:

    • 獨立原子:mockist,被我們推翻了。當然,最底部的函數可能沒有外部依賴,那單測它就夠了。

    • 自上而下(紅線):從入口函數往下測。實踐的過程中,我發現很難執行,因為我從入口處就要想好每一次調用都需要返回哪些數據及格式,串起來一個case已經非常不易。

    • 自下而上(黃線):我們發現,入口函數,往往沒什么邏輯,調用另一個函數然后拿到響應返回。所以入口函數,也許不用寫?我們繼續往下看,每一次調用的函數都看,也調出了以往的線上線下bug,我們發現出現問題的代碼部分往往是調用鏈的底端,尤其是涉及計算、復雜分支循環等。而且,底端的函數往往可測性較好。

    因此,考慮兩方面,我們選擇自下而上設計來選擇函數編寫case

  • 底部的函數可測性通常很好

  • 核心邏輯比較多,尤其涉及計算、拼接,分支的。


  • 可測性問題的解決——重構

    導致無法寫單測的重要原因是,代碼可測性不好。如果一個函數八九十行、二三百行,基本就是不可測的,或者說“不好測的”。因為里面邏輯太多了,從第一行到最后一行都經歷了什么,各種函數調用外部依賴,各種if/for,各種異常分支處理,寫一個case的代碼行數可能是原函數的幾倍。


    因此,推動單測走下去,重構提升可測性是必須環節。而且,通過重構,代碼結構間接清晰了,更可讀可維護,更容易發現和定位問題。


    常見的問題:重復代碼、魔法數字、箭頭式的代碼等


    推薦的理論書籍是《重構:改善既有代碼的設計》第二版、《clean code》

    我輸出了一篇關于重構的文章。


    使用codecc(騰訊代碼檢查中心)的圈復雜度、函數長度來評估代碼結構質量,我們與開發一起學習,一起實踐,不斷有成果輸出。


    對于箭頭式的代碼,可考慮如下步驟:

  • 多使用衛語句,先判斷異常,異常return

  • 將判斷語句抽離

  • 將核心部分抽離為函數


  • 用例維護,可讀性、可維護性、可信賴性

    用例設計要素

    • 將內部邏輯與外部請求分開測試

    • 對服務邊界(interface)的輸入和輸出進行嚴格驗證

    • 用斷言來代替原生的報錯函數

    • 避免隨機結果

    • 盡量避免斷言時間的結果

    • 適時使用setup和teardown

    • 測試用例之間相互隔離,不要相互影響

    • 原子性,所有的測試只有兩種結果:成功和失敗

    • 避免測試中的邏輯,即不該包含if、switch、for、while等

    • 不要保護起來,try…catch…

    • 每個用例只測試一個關注點

    • 少用sleep,延緩測試時長的行為都是不健康的

    • 3A策略:arrange,action,assert



    用例可讀性

    • 標題要明確表明意圖,如Test+被測函數名+condition+result。case失敗后,通過名字就知道哪個場景失敗,而不用一行行再讀代碼。將來維護這個測試代碼的,可能是其他人,我們需要讓別人容易讀懂

    • 測試代碼的內容要清晰,3A原則:arrange,action,assert 分成三部分。數據準備部分arrange如果代碼行較多,考慮抽離出去。

    • 斷言的意圖明顯,可以考慮將魔法數字變為變量,命名通俗易通

    • 一個case,不要做過多的assert,要專一

    • 和業務代碼的要求一致,都要可讀



    用例可維護性

    • 重復:文本字符串重復、結構重復、語義重復

    • 拒絕硬編碼

    • 基于意圖的設計。不要因為業務代碼重構一次,就導致一批case失敗

    • 注意代碼的各種壞味道,可參見《重構》第二版


    用例可信賴性

    單元測試,小而且運行快,它不是為了發現本次的bug,更是為了放在流水線上 努力發現每一次MR是否產生了bug。單測運行失敗,唯一的原因只應該是出現bug,而不是因為外部依賴不穩定、基于實現的涉及等,長期的失敗將失去單元測試的警示作用,“狼來了”的故事是慘痛的教訓。

    • 非被測程序缺陷,隨機失敗的case

    • 永不失敗的case

    • 沒有assert的case

    • 名不副實的case


    ?新聞單元測試的推動過程

    我們提到,對單元測試的實踐分為4個階段,每階段均有目標。


    第一階段? 會寫,全員寫,不要求寫好

    • 由上而下的推動,從總監到組長,極力支持,毫無猶豫,使組員情緒高漲

    • 快速確定單測框架,熟練使用

    • 結合開發需求,輸出各場景下 單測框架的使用方法,包括assert、mock,table-driven等

    • 封裝http2WebContext,方便生成context對象

    • 多次培訓,講解單測理論及框架使用

    • 各團隊(終端、接入層)指定單測接口人,由他先嘗螃蟹。他是最熟悉框架使用,在前期寫最多case的人

    • 在磨合好單測框架的集成使用后,啟動會,部分同學先試點使用,確保連續兩個迭代,這幾個同學都有case輸出

    • 每個迭代總結數據中,加入單測相關數據:組長和總監非常關注單測數據信息,針對性鼓勵提升case數量和代碼行數


    第二階段 寫好,有效,全員寫

    • 測試同學探索出mock的正確使用方法、用例設計的正確思路,分享給團隊,經過探討達成一致

    • 結對編程,每迭代結對2-3個開發,共同寫case,互相提升。


    這里的結對是靈活的:有的開發,只需用半天的時間給他講框架使用,同他練習,他就可以上手了不需要再擔心;有的開發,會分給測試同學需求,測試同學寫完case后,開發review學習,并嘗試寫出自己的第一個case;有的開發,一開始可能不太接受,以需求不適合單測為理由,觀察了一段時間,他發現其他人都寫了,也沒那么難,對團隊也有利,他甚至會主動找到測試同學教他寫case。

    • 測試同學對開發提交的case進行review,跟進開發修改后重新MR

    • 連續兩個迭代,邀請dot老師、喬幫主進行case review,效果非常好

    • 對迭代的單測數據分析,關注需求覆蓋度、人員覆蓋度,case增量

    • 組長持續鼓勵支持單測

    • 每迭代的需求增加“單元測試”字段,由組長評估后置位。不帶單測的MR不予通過,單測也要被review


    第三階段 可測性提升

    • 測試和開發共同學習《重構》第二版,每周有分享會

    • 某些骨干同學優先重構自己的代碼

    • 測試同學嚴格要求,先保證有單測,然后小步重構,每一步均有單測保障

    • 通過流水線的codecc掃描,圈復雜度和函數長度必須達標,不可人工干預其通過


    第四階段 TDD

    • 先不保證開發同學做到TDD,門檻還是挺高的,而且需要在線下熟練之后再運用到業務開發中

    • 逐步推動開發將業務代碼和測試代碼同步編寫,而不是完成業務代碼后再補case

    • 測試同學練成TDD


    流水線

    單測要放在流水線上跑,客戶端和后臺都配好了流水線,保證每次push和MR都運行一次,發報告。


    對于go的單測,新聞接入層各模塊是通過MakeFile來編譯,因為要導入一些環境變量,所以我將go test集成在MakeFile中,執行make test即可運行該模塊下所有的測試用例。

    GO = go CGO_LDFLAGS = xxx CGO_LDFLAGS += xxx CGO_LDFLAGS += xxx CGO_LDFLAGS?+=?xxx TARGET?=aaa export CGO_LDFLAGS all:$(TARGET) $(TARGET): main.go $(GO) build -o $@ $^ test: CFLAGS=-g export CFLAGS $(GO) test $(M) -v -gcflags=all=-l -coverpkg=./... -coverprofile=test.out ./... clean: rm -f $(TARGET)

    注:上述做法,只能生成被測試的代碼文件的覆蓋率,無法拿到未被測試覆蓋率情況??梢栽诟夸浗ㄒ粋€空的測試文件,就能解決這個問題,拿到全量代碼覆蓋率。

    //main_test.go package main import ( "fmt" "testing" ) func TestNothing(t *testing.T) { fmt.Println("ok") }

    流水線加上流程

    # cd ${WORKSPACE} 可進入當前工作空間目錄 export GOPATH=${WORKSPACE}/xxx pwd echo "====================work space" echo ${WORKSPACE} cd ${GOPATH}/src for file in `ls`: do if [ -d $file ] then if [[ "$file" == "a" ]] || [[ "$file" == "b" ]] || [[ "$file" == "c" ]] || [[ "$file" == "d" ]] then echo $file echo ${GOPATH}"/src/"$file cp -r ${GOPATH}/src/tools/qatesting/main_test.go ${GOPATH}/src/$file"/." cd ${GOPATH}/src/$file make test cd .. fi fi done

    ?附錄. 資料
    • 《測試驅動開發》

    • 《單元測試的藝術》

    • 《有效的單元測試》

    • 《重構,改善既有代碼的設計》

    • 《修改代碼的藝術》

    • 《測試驅動開發的三項修煉》

    • 《xUnit Test Patterns》

    • mock七宗罪

    總結

    以上是生活随笔為你收集整理的从头到脚说单测——谈有效的单元测试的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    国产视频999 | www黄色com | 欧美视频在线观看免费网址 | 久久草网| 99久久久国产精品 | 青草视频网 | 久久精品999 | 成人午夜精品福利免费 | 一区二区三区四区五区在线 | a黄色片 | 中日韩在线视频 | 一区二区三区日韩精品 | 日本bbbb摸bbbb| 伊人va| 欧美激情综合色 | 久久国产精品99精国产 | 国产系列精品av | 国产视频 久久久 | 国产精品99页 | 天天天干 | 97伊人网| 日韩超碰 | 免费日韩 精品中文字幕视频在线 | 久久免费一 | 狠狠干,狠狠操 | 精品国产乱码久久久久久三级人 | 热久在线 | 一区二区三区四区免费视频 | 97精品久久人人爽人人爽 | 亚洲区另类春色综合小说校园片 | 日韩精品专区在线影院重磅 | 中文成人字幕 | www成人av | 在线免费观看视频一区 | 久草在线久| 操操日日 | 久热av在线 | 久久久久久久久电影 | 欧美一级激情 | 人人要人人澡人人爽人人dvd | 91精品在线视频观看 | 亚洲3级| 亚洲欧美色婷婷 | 高清av免费看 | 国产精品视频你懂的 | 午夜骚影 | 久久无码av一区二区三区电影网 | 国产精品视频最多的网站 | 国产成人精品久久二区二区 | 日韩特级黄色片 | 亚洲精品一区二区三区在线观看 | 夜夜夜夜夜夜操 | 婷婷去俺也去六月色 | 超碰在线网 | 国产福利在线不卡 | 狠狠网 | 一区二区免费不卡在线 | 日本特黄特色aaa大片免费 | 丁香六月中文字幕 | 日韩精品一区二区三区电影 | 在线亚洲成人 | 91成人精品一区在线播放69 | 色视频网站在线观看一=区 a视频免费在线观看 | 在线观看 国产 | 欧美日韩中文视频 | 四虎在线观看精品视频 | 狠狠狠色丁香婷婷综合激情 | 精品99久久 | 国产精品网红直播 | 白丝av免费观看 | 久久手机免费观看 | 日韩在线观| 久久久久久国产精品999 | 国产精品亚洲成人 | 日韩理论片在线观看 | 久久久资源网 | 91九色视频在线观看 | 最新影院 | 日本在线观看中文字幕无线观看 | 丁香5月婷婷 | 国产最顶级的黄色片在线免费观看 | 日韩欧美一区二区三区在线 | 久久久久一区二区三区四区 | 人人超碰免费 | 日韩大片免费观看 | 欧美日韩精品在线视频 | 日日天天av| 国产精品亚洲片夜色在线 | 日韩欧美精品一区二区三区经典 | 国产成人一区二区啪在线观看 | 精品国产一区二区三区久久久蜜月 | 欧美激情视频一二三区 | 999视频网站 | 日产乱码一二三区别免费 | 在线观看精品视频 | 亚洲午夜精品一区二区三区电影院 | 国产美腿白丝袜足在线av | 色综合在 | 久久精精品视频 | 精品久久综合 | 精品国产福利在线 | 国产专区视频在线 | 四虎影视成人永久免费观看视频 | 免费看一级一片 | 国产精品一区二区久久精品爱微奶 | 黄污污网站 | 国产精品成人自拍 | 夜色成人网 | 国产成人一区二区三区 | 国产精品久久久久毛片大屁完整版 | 91免费的视频在线播放 | 亚洲欧美日韩一区二区三区在线观看 | 亚洲综合色播 | 久久一久久 | 亚洲成人av电影在线 | 亚洲成人av电影在线 | 天天操天天射天天添 | 福利精品在线 | 免费观看av网站 | 青草视频在线免费 | 久久精品久久精品久久39 | 亚洲最新av网站 | 国产精品成久久久久三级 | 少妇bbb搡bbbb搡bbbb′ | va视频在线 | 欧美一级电影免费观看 | 涩涩网站在线看 | 免费观看一级成人毛片 | 超碰在线观看av.com | 国产无遮挡猛进猛出免费软件 | a天堂中文在线 | 日韩高清无线码2023 | av黄色国产 | 婷婷激情综合五月天 | 国产精品高潮呻吟久久av无 | 伊人天堂av| 一区二区视频在线看 | 日韩欧美综合视频 | 激情喷水 | 国产二区视频在线观看 | 色久av| 亚洲视频axxx | 五月激情天 | 亚洲麻豆精品 | 91热在线 | 久久久久免费视频 | 手机在线永久免费观看av片 | av在线com| 日韩欧美在线观看一区二区三区 | 亚洲日本va午夜在线电影 | 日本性xxxxx 亚洲精品午夜久久久 | 亚洲精品视频久久 | 婷婷激情综合网 | 天天色婷婷| 91人人揉日日捏人人看 | 九色精品在线 | 69av在线播放 | 中文在线免费看视频 | 网站在线观看你们懂的 | 97电影院在线观看 | 亚洲资源片 | 亚洲va天堂va欧美ⅴa在线 | 日韩黄色免费看 | 国产黄色av影视 | 91成人看片 | 欧美伦理一区二区三区 | 天天干天天天天 | 成人永久视频 | 九月婷婷人人澡人人添人人爽 | 精品999| 日本三级中文字幕在线观看 | 狠狠躁日日躁狂躁夜夜躁av | 伊人伊成久久人综合网小说 | 黄色成人在线 | 精品国自产在线观看 | 一级黄色片毛片 | 国产精品99久久久久久有的能看 | 国精产品999国精产品视频 | 精品久久久久久久久中文字幕 | 国产日本亚洲高清 | 久久国产精品久久w女人spa | 摸阴视频 | 久久刺激视频 | 久久99久久99精品 | 麻豆久久 | 久久视频这里有久久精品视频11 | 国色天香第二季 | 在线视频 国产 日韩 | av免费片| 久久在线观看 | 国产精品一区二区久久 | 精品国内自产拍在线观看视频 | 天天干天天搞天天射 | 国色天香在线 | 天海冀一区二区三区 | 亚洲国产精品va在线看黑人 | 久久久五月天 | av大片网址 | 国产一区二区三区四区大秀 | 日本性生活一级片 | 欧美一级视频在线观看 | 日本中文字幕网 | 国产高清视频免费 | 99精品久久久久久久久久综合 | 亚洲综合色激情五月 | 久久综合视频网 | 精品一区二区免费 | 国产成人精品在线 | 精品国产99国产精品 | 一区二区视频在线观看免费 | www.婷婷色 | 九九在线高清精品视频 | 91精品资源 | 久草在线费播放视频 | www.久久色 | 亚洲干视频在线观看 | 欧美一性一交一乱 | 国产精品av久久久久久无 | 国产一区在线免费观看视频 | 日本韩国精品一区二区在线观看 | 日韩精品在线看 | 久久99免费 | 黄色美女免费网站 | 国产福利一区二区三区在线观看 | 又粗又长又大又爽又黄少妇毛片 | 亚洲精品欧美视频 | 中文字幕色网站 | 国产大片黄色 | 日韩乱码中文字幕 | 久久久夜色 | 四虎影视www| 99免费精品| 狠狠gao| 丁香六月国产 | 亚洲国产精品免费 | 天天操天天射天天爱 | 天天性天天草 | 三级在线播放视频 | 一区二区三区四区五区在线 | 日韩欧美在线观看 | 久久夜色精品国产欧美乱极品 | av高清在线| 国产成人精品在线播放 | 日韩sese | 亚洲91视频 | 国内丰满少妇猛烈精品播 | 99久热在线精品视频观看 | 一区二区激情视频 | 色婷婷九月| 国产96在线视频 | 日韩亚洲欧美中文字幕 | 精品一区在线看 | 国产日韩在线一区 | 午夜一级免费电影 | 午夜电影久久久 | 久艹视频在线观看 | 成人av网页 | 免费观看www7722午夜电影 | 日本xxxxav| 日韩伦理一区二区三区av在线 | 中文在线字幕观看电影 | 特级aaa毛片| 日韩高清免费在线 | 国产99一区 | 不卡视频国产 | 国产精品毛片一区二区 | 香蕉在线影院 | 欧美日在线| 国产免费观看久久黄 | 久久国产热| 一区在线观看视频 | 手机在线永久免费观看av片 | 精品在线观看一区二区三区 | 日韩av手机在线看 | 深夜精品福利 | 色资源网免费观看视频 | 人人澡人人添人人爽一区二区 | 操操日日 | 天天操综| 中文字幕 国产专区 | 天天色成人网 | 8x成人在线| 国产成人一区二区三区久久精品 | 精品视频在线播放 | 亚洲综合色婷婷 | 日韩av中文在线 | 我要色综合天天 | 日韩av快播电影网 | 亚洲精品乱码久久久久久久久久 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 国产精品一区久久久久 | 五月综合激情婷婷 | 国产精品涩涩屋www在线观看 | 一区二区三区在线视频111 | 欧美天天综合 | 久久亚洲区 | 久久精品国产精品亚洲 | 自拍超碰在线 | 国产精品av免费观看 | 69欧美视频 | 色综合久久88色综合天天免费 | 国产中文字幕网 | 欧美韩国日本在线观看 | 欧美一级免费在线 | 国产视频精品免费 | 在线播放一区二区三区 | 五月天高清欧美mv | 九九欧美| 日韩免费一级电影 | av免费电影网站 | 蜜桃av观看| 欧美一区在线观看视频 | 国产91学生粉嫩喷水 | 国产成人精品在线播放 | 国产福利在线免费观看 | 中文字幕欧美日韩va免费视频 | 久综合网| 一级欧美一级日韩 | 男女拍拍免费视频 | 天天色官网 | 97精品国产97久久久久久粉红 | 九九交易行官网 | 少妇bbbb搡bbbb搡bbbb | 欧美一进一出抽搐大尺度视频 | 91av蜜桃| 91麻豆产精品久久久久久 | 91av在| 激情开心色 | 精品91在线 | 最新av网址在线观看 | 成人在线免费av | 2020天天干夜夜爽 | 超碰在线公开免费 | 国产系列精品av | 欧美日韩精品在线观看 | 成人影音av | 亚洲日日射 | 麻豆系列在线观看 | 手机成人在线 | 精品欧美一区二区精品久久 | 免费国产视频 | 国产精品不卡在线 | 欧美 亚洲 另类 激情 另类 | 日韩高清在线一区二区三区 | 国产精品一区二区在线 | 中文国产成人精品久久一 | 人人爱人人做人人爽 | 欧美色图东方 | 久久视频这里有久久精品视频11 | 黄色软件视频大全免费下载 | 亚洲精品视频网站在线观看 | 日韩精品一区二区三区不卡 | 国产精品久久久久毛片大屁完整版 | av一级一片| 欧美成人在线网站 | 福利电影一区二区 | 久久视频免费看 | 国产小视频在线看 | 久久国产成人午夜av影院宅 | 蜜桃av人人夜夜澡人人爽 | 国产麻豆剧传媒免费观看 | 国产精品网站 | 色九九视频 | 97av视频在线观看 | 国产尤物视频在线 | 国产精品一区二区三区在线免费观看 | 亚洲乱码精品久久久久 | 国产精品一区二区无线 | 国产精品成人品 | 韩国一区二区在线观看 | 国产在线观看91 | 免费a v在线 | 成人免费视频播放 | 亚州免费视频 | 免费观看十分钟 | 久久综合加勒比 | 久草视频在线免费看 | 成人午夜电影在线播放 | 国产成人精品一区在线 | 久久精品—区二区三区 | 国产成人精品亚洲日本在线观看 | 日韩中文免费视频 | 中文字幕永久在线 | 99久高清在线观看视频99精品热在线观看视频 | 精品一区在线 | 日韩理论片在线 | 五月天av在线 | 久久理论电影网 | 四虎成人精品在永久免费 | 亚洲精品免费在线 | 日产乱码一二三区别免费 | 人人爽人人爽人人爽学生一级 | 亚洲精品www久久久 www国产精品com | 在线视频福利 | 久久人人97超碰com | 亚洲 欧美变态 另类 综合 | 免费99精品国产自在在线 | 午夜电影一区 | 超碰人人射 | 日韩免费网站 | 深夜免费福利 | 中文不卡视频在线 | 日韩mv欧美mv国产精品 | 美女在线观看av | 日韩高清一二三区 | 久草视频在线免费 | 久久国产免费看 | 韩国精品在线观看 | 狠狠干夜夜操天天爽 | 深爱五月激情五月 | 久久激情精品 | 狠狠色伊人亚洲综合网站野外 | 国产精品美女久久久久久网站 | 久久国产精品偷 | 久久国产一区 | 久久亚洲成人网 | 国产精品成人av在线 | 激情五月婷婷激情 | 91日韩在线专区 | 91毛片视频| 亚洲成人精品国产 | 丁香视频 | 久久久久久久久久久网站 | 精品免费在线视频 | 欧美成人在线网站 | 丝袜精品视频 | 久久免费视频在线观看 | 国产黑丝一区二区 | 中文字幕在线影院 | 99久久精品午夜一区二区小说 | 亚洲美女视频网 | 少妇bbbb揉bbbb日本 | 午夜精品久久久久久久久久 | se婷婷 | 久久99国产精品二区护士 | 日韩国产欧美在线播放 | 91中文字幕网| 久久深夜 | 精品国产网址 | 欧美一区在线看 | 日韩电影一区二区三区 | 狠狠色噜噜狠狠狠狠2022 | 亚洲电影影音先锋 | 五月婷婷视频 | 日韩在线视频网 | 奇米影视8888在线观看大全免费 | 伊人五月 | 国内视频在线 | av免费电影在线 | 成全在线视频免费观看 | 欧美黄色软件 | 天天干天天色2020 | av黄色免费看 | 国产主播99 | 91精品色| 黄色大片av | 午夜视频不卡 | 狠狠躁夜夜躁人人爽超碰91 | 日本系列中文字幕 | 免费 在线 中文 日本 | 午夜精品一区二区三区视频免费看 | 成人免费观看视频大全 | 最近2019年日本中文免费字幕 | 91在线网站| 麻豆91精品| 人人舔人人干 | 超碰人人在线观看 | 精品国产精品久久 | 欧美视频18| 成人av一二三区 | 91久久精| 欧美片网站yy | 天天干夜夜干 | 中文字幕中文字幕在线一区 | 国产成人精品一区二区三区福利 | 午夜在线资源 | 91麻豆精品国产自产在线游戏 | 91视频免费看网站 | 天天综合网久久 | 麻花豆传媒mv在线观看网站 | 久草在线视频免费资源观看 | 日韩免费在线观看 | 亚洲欧美日韩国产精品一区午夜 | 日韩精品中文字幕在线不卡尤物 | 日本在线视频一区二区三区 | www久久国产 | 国产婷婷在线观看 | 黄色网址a | 久久久一本精品99久久精品66 | 久久99久久精品国产 | 国产九色在线播放九色 | 四虎影视成人精品国库在线观看 | 成人亚洲网 | 午夜av免费 | 青草视频网 | 五月天视频网 | 国产精品爽爽久久久久久蜜臀 | 91精品国产自产在线观看永久 | 国产精品一区在线观看你懂的 | 欧美色就是色 | 91在线免费播放视频 | 成人动漫精品一区二区 | 51久久成人国产精品麻豆 | 亚洲极色| 精品国产福利在线 | 18国产精品福利片久久婷 | 久草在线最新 | 天天色天天操天天爽 | 国产激情久久久 | 久久久私人影院 | 日韩在线视频网址 | 在线视频观看亚洲 | 一本到视频在线观看 | 日韩系列在线观看 | 日韩黄色免费电影 | 欧美日韩免费在线视频 | 久久黄色网页 | 国产小视频免费观看 | 久久久精品视频成人 | 成人在线免费视频观看 | 国产精品久久久久毛片大屁完整版 | 中文字幕资源网在线观看 | 欧美analxxxx| 日韩免费一级a毛片在线播放一级 | 99视频这里有精品 | 亚洲国产视频a | 麻豆成人精品视频 | 国产精品女同一区二区三区久久夜 | 五月在线 | 在线观看视频国产一区 | 免费久久99精品国产 | 午夜久久久久久久 | 日日日日 | 香蕉在线观看 | 在线免费观看国产视频 | 天干啦夜天干天干在线线 | 国产精品久久久久久久久久东京 | 黄色av电影网 | 久草在线手机视频 | 中文字幕在线免费播放 | 五月天综合网站 | 人成在线免费视频 | 日韩一区二区三区在线观看 | 免费av在线网 | 91视频在线国产 | 综合久久久久久 | 天天干天天做 | 日韩免 | 国产一区麻豆 | 国内精品久久天天躁人人爽 | 一级黄色电影网站 | 亚洲精品久久久久www | 六月色丁香 | 500部大龄熟乱视频使用方法 | 欧美一级特黄高清视频 | 欧美日韩在线观看视频 | 久草视频在线免费播放 | 国产视频丨精品|在线观看 国产精品久久久久久久久久久久午夜 | 九九久久久久久久久激情 | 一级成人免费视频 | 国产高清视频免费观看 | 激情久久久久久久久久久久久久久久 | 亚洲狠狠操 | 日日夜色 | 中文字幕在线观看一区二区 | 91在线播| 91麻豆精品国产91久久久无需广告 | 精品视频123区在线观看 | 久久国内精品99久久6app | 成人免费91 | 美女搞黄国产视频网站 | 国产一区二区三区午夜 | 97视频资源 | 国产黄色精品在线观看 | 毛片网在线 | 99婷婷狠狠成为人免费视频 | 2019天天干天天色 | 久草视频看看 | 国产精品一区在线播放 | 果冻av在线 | 一级片免费观看视频 | 九色91视频| 亚洲日本一区二区在线 | 国产一区成人在线 | 日韩在线视频播放 | 精品一区二区免费 | 精品国产伦一区二区三区观看体验 | 色综合天天狠天天透天天伊人 | 最近中文字幕mv免费高清在线 | 欧美最猛性xxxxx免费 | 国产一级视频免费看 | www.天天干 | 国产成人av电影在线 | 成人午夜电影免费在线观看 | 国产精品久久久久久久久久久杏吧 | 免费福利视频导航 | 91色影院 | 国产成人精品一区二区 | 久久久久久综合网天天 | 成人资源在线观看 | 欧美日韩一区二区三区在线观看视频 | 国产成人精品久久亚洲高清不卡 | 中文字幕免费高清av | 高清一区二区 | 亚洲综合干 | 中文字幕久久精品亚洲乱码 | 久久综合色影院 | 少妇性aaaaaaaaa视频 | 91综合色 | 国产精品一区二区久久久 | 黄色免费网站 | 五月婷婷另类国产 | 91亚洲视频在线观看 | 久草在线资源观看 | 亚洲理论片 | 日韩欧美在线观看 | 亚洲免费精彩视频 | 在线观看中文字幕2021 | 精品国产乱码久久久久久三级人 | 日韩在线中文字幕 | 福利视频网址 | 精油按摩av | 人人干人人爽 | 四虎国产精品成人免费4hu | 91在线最新 | 久久夜靖品 | 欧美91成人网 | 四虎成人精品永久免费av | 日韩电影久久 | 91国内在线 | 久久国产精品一国产精品 | 超碰com| 中文欧美字幕免费 | 一区二区三区在线免费 | 一区二区三区动漫 | 国产一区二区三区免费观看视频 | 久久久精品国产免费观看同学 | 国产原创在线观看 | www.夜夜干.com| 免费在线观看国产黄 | 久久精品99精品国产香蕉 | 天天操天天干天天干 | 九九热在线免费观看 | 在线视频精品播放 | 91av在线看 | 日韩v在线91成人自拍 | .国产精品成人自产拍在线观看6 | 蜜臀av性久久久久蜜臀aⅴ四虎 | 日韩欧美精品在线视频 | 国产成人一区在线 | 欧洲精品在线视频 | 在线免费视频 你懂得 | 国产手机视频在线播放 | 日本狠狠干 | 亚洲激情视频在线观看 | 天天干天天看 | 精品国产1区2区3区 国产欧美精品在线观看 | 国产日产欧美在线观看 | 在线之家免费在线观看电影 | 香蕉视频在线看 | 亚洲成人av片在线观看 | 色鬼综合网 | 97在线观看视频免费 | 国产成人l区 | 在线v片免费观看视频 | 91亚·色| 亚洲色图22p | 国产精品视频你懂的 | 精品嫩模福利一区二区蜜臀 | 狠狠狠色丁香综合久久天下网 | 91精品网站 | 亚洲一区久久久 | 久久精品91久久久久久再现 | 日韩欧美精品免费 | 欧美久久久久久久久中文字幕 | 日韩视频区 | 久久99免费 | 青草视频在线播放 | 在线观看免费色 | 成人午夜av电影 | a'aaa级片在线观看 | 欧美一区日韩精品 | 国产高清精品在线 | 免费网站黄 | 国产99久久久欧美黑人 | 日韩精品一区二区三区免费视频观看 | 日韩在线观看视频一区二区三区 | 福利电影久久 | 黄色av大片 | av高清一区 | 精品国内自产拍在线观看视频 | 色婷婷综合久久久久中文字幕1 | 日韩在线视频二区 | 中文字幕在线日亚洲9 | 国产精品毛片一区 | 狠狠色噜噜狠狠狠狠2021天天 | 亚洲国产大片 | 久久伊人综合 | 99在线高清视频在线播放 | 日女人免费视频 | 91网在线| 青青久视频 | 国产 字幕 制服 中文 在线 | 久草精品视频在线观看 | 国产乱码精品一区二区蜜臀 | 最新日本中文字幕 | 在线免费观看的av | 不卡视频在线 | 亚洲视频在线看 | 国产又粗又猛又黄视频 | 美女久久久久久久久久久 | 国产成人精品一区二三区 | 婷婷免费视频 | 国产一二区在线观看 | 在线免费观看欧美日韩 | 国产精品密入口果冻 | 国产精品扒开做爽爽的视频 | 最新的av网站 | 国产中文字幕网 | 91大神一区二区三区 | 不卡的av | 久久高清 | 黄色软件在线看 | 天天狠狠干 | av成人免费 | 亚洲草视频| 国产成人精品999 | 在线观看av网 | 久艹视频在线观看 | 人人添人人澡人人澡人人人爽 | 午夜av一区 | 日韩精品欧美精品 | 狠狠黄 | 在线观看v片 | 免费日韩 精品中文字幕视频在线 | 欧美日本不卡视频 | 国产精品日韩在线播放 | 九九精品视频在线观看 | 黄色国产高清 | 91免费网 | www色综合 | 亚洲精品国产精品国自产观看浪潮 | 免费一级特黄毛大片 | 中文在线免费观看 | 国产亚洲成人精品 | 国产日本在线播放 | 日韩欧美精品在线视频 | 中文字幕免费观看视频 | 黄免费网站 | 91精品免费在线 | 免费在线观看视频一区 | 18国产精品白浆在线观看免费 | 欧美天天综合网 | 国产精品久久久久久久久久不蜜月 | 99久久久久免费精品国产 | 国产高清在线a视频大全 | 四虎影视国产精品免费久久 | 国产玖玖精品视频 | 99久久国产免费,99久久国产免费大片 | 成人久久精品 | 欧美日韩一区二区三区不卡 | 亚洲激情网站免费观看 | 国产尤物在线视频 | 亚洲国产小视频在线观看 | 亚州精品天堂中文字幕 | 人人干人人做 | 国产婷婷 | 国产精品18videosex性欧美 | 天天插伊人| a在线免费观看视频 | 久草资源在线观看 | 国产午夜精品在线 | 免费日韩电影 | 久草视频资源 | 国产精品亚 | 日韩av电影免费在线观看 | 亚洲精品自在在线观看 | 99精品小视频| 亚洲精品国产成人av在线 | 夜夜骑天天操 | 五月婷婷丁香在线观看 | 日本激情动作片免费看 | 国产极品尤物在线 | 午夜123| www黄色com| 免费看污黄网站 | 国内精品美女在线观看 | 91激情小视频 | 国产成人一区二区在线观看 | av电影 一区二区 | 国产91精品一区二区麻豆亚洲 | 国产成人黄色在线 | 中文字幕在线观看资源 | 精品极品在线 | 插婷婷 | 日韩黄色av网站 | 亚洲欧美成人 | 午夜国产福利在线 | 国产精品99免费看 | 夜夜骑天天操 | 五月婷婷激情五月 | a成人在线| 久久免费精品一区二区三区 | 天天草天天干天天 | 久久成人高清视频 | 色综合久久久久久久久五月 | 99精品国产一区二区三区麻豆 | 中文av字幕在线观看 | 久久久久这里只有精品 | 美女精品网站 | 天天要夜夜操 | 久久久久国产精品免费免费搜索 | 久艹在线观看视频 | 久草精品视频在线观看 | 麻豆国产视频下载 | 国内精品久久久久久久影视麻豆 | 在线观看日韩中文字幕 | 奇米影视在线99精品 | 午夜久久福利 | 911精品视频 | 久久综合久久伊人 | 香蕉在线观看 | 免费视频久久久久久久 | 欧美 日韩 国产 成人 在线 | 99热精品国产一区二区在线观看 | 91av免费在线观看 | 综合网中文字幕 | 亚洲电影在线看 | 亚洲电影在线看 | 国内99视频 | av在线免费在线观看 | 91av电影在线| 91大神电影 | 午夜视频二区 | 久久久久久高潮国产精品视 | 最新真实国产在线视频 | 国产一级精品绿帽视频 | 国产99久久九九精品免费 | 最近中文字幕mv免费高清在线 | 91丨九色丨国产在线观看 | 国产精品黄色av | 93久久精品日日躁夜夜躁欧美 | 久久精品99国产精品 | 亚洲国产电影在线观看 | 国产精品久久久久久久久久久杏吧 | 日韩在线视频免费看 | 日韩精品在线免费观看 | 欧美看片 | 91免费高清 | 亚洲欧美va | 中文字幕在线观看免费高清电影 | 黄污视频网站大全 | 日本中文字幕在线一区 | 97国产在线观看 | 亚洲人在线7777777精品 | 在线成人短视频 | 亚洲综合成人专区片 | 国产视频亚洲精品 | 久久久久高清毛片一级 | 日韩字幕在线观看 | 99久久影视| 国产999精品久久久久久绿帽 | 五月婷婷毛片 | 国产天天爽| 国产高清黄 | 99精品热视频只有精品10 | 国产成人黄色网址 | 2019精品手机国产品在线 | 日产乱码一二三区别在线 | 国产麻豆剧果冻传媒视频播放量 | 国产xx在线 | 黄色免费看片网站 | 奇米先锋| 国产999精品久久久久久绿帽 | 欧美色一色 | 国产精品嫩草影视久久久 | 热久久这里只有精品 | 久久激情婷婷 | 深爱五月激情网 | 黄色a在线观看 | 九九久久在线看 | 婷婷五月色综合 | 久久特级毛片 | 欧美精品乱码久久久久 | 一区二区精品久久 | 天天操天天干天天综合网 | 亚洲精品在 | 国产成人精品a | 国产色黄网站 | 人人看人人艹 | 久久精品综合网 | 九九热免费精品视频 | 日韩在线视频二区 | 日本中文字幕观看 | 天天操比 | 亚洲综合爱 | 久久伦理电影 | 亚洲天堂在线观看完整版 | 免费看网站在线 | 日韩美一区二区三区 | 亚洲精品国产精品久久99热 | sm免费xx网站 | 久久久久久久久爱 | 欧美国产日韩一区二区三区 | 久久国产一区二区三区 | 日韩久久在线 | 天天综合成人网 | 久久国产经典视频 | 黄色成人av在线 | 国内视频在线观看 | 天天操天天操天天操天天操天天操天天操 | 日韩一区二区三区不卡 | 最新av电影网站 | 亚州av成人 | av福利在线播放 | 国产糖心vlog在线观看 | 国产一卡二卡四卡国 | 日韩av免费一区二区 | 国产婷婷一区二区 | 蜜臀久久99精品久久久无需会员 | 中文字幕一区二区三区乱码在线 | 91最新在线视频 | 97人人澡人人添人人爽超碰 | 久久久久国产成人精品亚洲午夜 | 国产1区在线 | 二区三区在线视频 | 久久久久国产一区二区三区四区 | 日韩av一区二区三区四区 | 成人a免费 | 在线观看小视频 | 97福利视频 | 色婷婷av国产精品 | 欧美国产视频在线 | 久久福利影视 | 色婷婷狠狠 | 97精品国产97久久久久久久久久久久 | 成年人免费在线观看网站 | 免费久久视频 | 美国三级黄色大片 | 8x8x在线观看视频 | 在线观看免费一区 | 日日日操操 | 国产麻豆精品免费视频 | 全黄色一级片 | www国产精品com | www黄色 | 亚洲1区 在线 | 中文字幕在线久一本久 | 免费观看91视频大全 | a视频在线观看免费 | 99在线观看视频网站 | 四虎免费在线观看 | 久久不见久久见免费影院 | 在线观看亚洲国产 | 亚洲视频综合 | av免费线看 | 国语久久 | 天天色天天干天天色 | 久久久久久久久久久久久9999 | 丁香五月亚洲综合在线 | 日本成人a| 久久久激情视频 | 3d黄动漫免费看 | 日韩91在线 | 日韩精品一卡 | 免费精品在线视频 | 久久一区二区三区日韩 | 久久精品4 | 国产精品女视频 | 日韩中文字幕一区 | 欧美另类交人妖 | 久久久在线视频 | 视频在线观看亚洲 | 日本精品视频一区 | 综合天天 | 五月天综合色 | 免费黄色在线网站 | 91精品办公室少妇高潮对白 | 毛片永久免费 | 五月天丁香 | 国产精品久久久久久久久久久久午夜片 | 国产精品igao视频网网址 | 久久一区二区免费视频 | 久久蜜臀一区二区三区av | 在线色亚洲 | 在线观看色网 | 五月天com| 国产成人av电影在线 | 久草视频在线免费播放 | 在线亚洲欧美日韩 | 一级片视频在线 | 91免费高清视频 | 免费看污黄网站 | 欧美性免费 | 精品久久一二三区 | 久久婷婷丁香 | 精品国产成人av | 国产精品99久久久久久人免费 |