精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Go項目實戰-學會對代碼邏輯層進行BDD測試

開發 項目管理
通過這幾節單元測試實戰的內容大家應該能體會到,我們為項目做好分層設計的一個優點--好測試。每個分層都有具體的職責,每塊代碼的邊界不至于過大,這樣我們做單元測試代碼寫起來會更簡單。

前面兩節我們的單元測試主要集中在對項目基礎設施層的代碼進行單元測試,針對Dao數據操作層我們講解了如何在不實際對項目數據庫進行CURD的情況下使用了sqlmock的方式進行單元測試。而對于外部API對接層則是教會大家用gock實現無侵入的HTTP Mock,對有API請求的代碼進行單元測試。

今天我們更進一步,從項目代碼的基礎設施層來到邏輯層和用戶接口層。邏輯層的代碼肯定更注重邏輯,所以我們在這里會引入goconvey 這個庫實現,讓它幫助我們實現BDD(行為驅動測試),goconvey支持樹形結構方便構造各種場景,讓我們能更容易地基于 goconvey 來組織的單測。本文大綱如下:

圖片圖片

goconvey 的 安裝命令如下:

go get github.com/smartystreets/goconvey

輸入命令后,安裝過程如下所示:

圖片圖片

關于goconvey的使用方法詳解,這里就不在給大家舉簡單的例子進行說明了,還是按照前面幾篇的風格,給大家提供一個我在公眾號上寫的 goconvey 入門詳解。

  • 使用 Go Convey 做BDD測試的入門指南

邏輯層單元測試實戰

我們項目各業務的核心邏輯都主要集中在領域服務 domainservice 中,按照我們為項目做的的單元測試目錄規劃,它的單元測試_test.go 文件都應該放在test/domainservice 目錄中。

.
|---test
|     |---controller    # controller 的測試用例
|     |---dao    # dao 的測試用例
|     |---domainservice # 邏輯層領域服務的測試用例
|     |---library # 外部API對接的測試用例

TestMain 入口設置

依照慣例,在每個要寫單元測試的package中,我門都需要在包內測試的統一入口TestMain中做一些公共基礎性的工作。

我們在TestMain中加上Convey 的SuppressConsoleStatistics和PrintConsoleStatistics,用于在測試完成后輸出測試結果。

package domainservice

import (
    "testing"
    . "github.com/smartystreets/goconvey/convey"
)

func TestMain(m *testing.M) {
// convey在TestMain場景下的入口
 SuppressConsoleStatistics()
 result := m.Run()
// convey在TestMain場景下的結果打印
 PrintConsoleStatistics()
 os.Exit(result)
}

這么設置后,輸出的測試結果會按照單測中Convey書寫的層級分層級顯示,這個輸出結果我會在下面的實戰案例中展示給大家。

注意這里convey包的導入方式使用了 import . 的語法,import . "github.com/smartystreets/goconvey/convey",這樣是為了方便大家直接使用 convey 包中的各種定義,無需再像 convey.Convey 這樣加包前綴。

實戰案例一:密碼復雜度的BDD測試

在案例一種我們找一個相對簡單的工具函數來演示怎么用convey幫助我們組織用例。我們在用戶注冊和重設密碼種使用過一個檢查用戶密碼復雜度的工具函數。

func PasswordComplexityVerify(s string) bool {
var (
  hasMinLen  = false
  hasUpper   = false
  hasLower   = false
  hasNumber  = false
  hasSpecial = false
 )
iflen(s) >= 8 {
  hasMinLen = true
 }
for _, char := range s {
switch {
case unicode.IsUpper(char):
   hasUpper = true
case unicode.IsLower(char):
   hasLower = true
case unicode.IsNumber(char):
   hasNumber = true
case unicode.IsPunct(char) || unicode.IsSymbol(char):
   hasSpecial = true
  }
 }
return hasMinLen && hasUpper && hasLower && hasNumber && hasSpecial
}

接下來我們就給 PasswordComplexityVerify 函數編寫測試用例。

func TestPasswordComplexityVerify(t *testing.T) {
 Convey("Given a simple password", t, func() {
  password := "123456"
  Convey("When run it for password complexity checking", func() {
   result := util.PasswordComplexityVerify(password)
   Convey("Then the checking result should be false", func() {
    So(result, ShouldBeFalse)
   })
  })
 })

 Convey("Given a complex password", t, func() {
  password := "123@1~356Wrx"
  Convey("When run it for password complexity checking", func() {
   result := util.PasswordComplexityVerify(password)
   Convey("Then the checking result should be true", func() {
    So(result, ShouldBeTrue)
   })
  })
 })
}

在這個測試函數中,首先我們從正向和負向兩個方面對函數進行單元測試,正向測試和負向測試都是什么呢,用通俗易懂的文字解釋就是:

  • 正向測試:提供正確的入參,期待被測對象返回正確的結果。
  • 負向測試:提供錯誤的入慘,期待被測對象返回錯誤的結果或者對應的異常。

通過這個例子,正好說一下在使用goconvy的過程中需要注意的幾個點:

  • Convey 可以嵌套的,這樣我們就可以構造出來一條測試的場景路徑,幫助我們寫出BDD風格的單測。
  • Convey 嵌套使用時函數的參數有區別。

最上層Convey 為Convey(description string, t *testing.T, action func())

其他層級的嵌套 Convey 不需要傳入 *testing.T,為Convey(description string, action func())

結合我們在 description 參數中的描述,我們就可以建立起來類似 BDD (行為驅動測試)的語義:

  • Given【給定某些初始條件】

Given a simple passowrd 給定一個簡單密碼

  • When 【當一些動作發生后】
  • When run it for password complexity checking 當對它進行復雜度檢查時
  • Then 【結果應該是】
  • Then the checking result should be false 結果應該是 false

BDD測試中的描述信息通常使用的是Given、When、Then引導的狀語從句,如果喜歡用中文寫描述信息也要記得使用類似語境的句子。

咱們用 go test -v 命令來看看測試運行的效果,我們可以看到輸出的測試結果會按照單測中Convey書寫的層級,分層級顯示。

圖片圖片

實戰案例二:用戶注冊的BDD測試

通過上面一個相對簡單的例子,相信大家對goconvey庫的使用已經有所了解,那么接下來我們再來看一下,怎么為邏輯層中那些復雜的代碼邏輯編寫單元測試。

我選用的是用戶注冊的領域服務方法,來給大家展示為業務邏輯代碼編寫單元測試,整個測試用 goconvey 組織用例的行為路徑,使用 gomonkey 對 RegisterUser 方法中依賴的其他方法進行Mock,整個測試方法的代碼如下:

func TestUserDomainSvc_RegisterUser(t *testing.T) {
 Convey("Given a user for RegisterUser of UserDomainSvc", t, func() {
  givenUser := &do.UserBaseInfo{
   Nickname:  "Kevin",
   LoginName: "kevin@go-mall.com",
   Verified:  0,
   Avatar:    "",
   Slogan:    "Keep tang ping",
   IsBlocked: 0,
   CreatedAt: time.Date(2025, 1, 31, 23, 28, 0, 0, time.Local),
   UpdatedAt: time.Date(2025, 1, 31, 23, 28, 0, 0, time.Local),
  }
  planPassword := "123@1~356Wrx"
var s *dao.UserDao
// 讓UserDao的CreateUser返回Mock數據
  gomonkey.ApplyMethod(s, "CreateUser", func(_ *dao.UserDao, user *do.UserBaseInfo, password string) (*model.User, error) {
   passwordHash, _ := util.BcryptPassword(planPassword)
   userResult := &model.User{
    ID:        1,
    Nickname:  givenUser.Nickname,
    LoginName: givenUser.LoginName,
    Verified:  givenUser.Verified,
    Password:  passwordHash,
    Avatar:    givenUser.Avatar,
    Slogan:    givenUser.Slogan,
    CreatedAt: givenUser.CreatedAt,
    UpdatedAt: givenUser.UpdatedAt,
   }
   return userResult, nil
  })

  Convey("When the login name of user is not occupied", func() {
   gomonkey.ApplyMethod(s, "FindUserByLoginNam", func(_ *dao.UserDao, loginName string) (*model.User, error) {
    returnnew(model.User), nil
   })
   Convey("Then user should be created successfully", func() {
    user, err := domainservice.NewUserDomainSvc(context.TODO()).RegisterUser(givenUser, planPassword)
    So(err, ShouldBeNil)
    So(user.ID, ShouldEqual, 1)
    So(user, ShouldEqual, givenUser)
   })
  })

  Convey("When the login name of user has already been occupied by other users", func() {
   gomonkey.ApplyMethod(s, "FindUserByLoginNam", func(_ *dao.UserDao, loginName string) (*model.User, error) {
    return &model.User{LoginName: givenUser.LoginName}, nil
   })
   Convey("Then the user's registration should be unsuccessful", func() {
    user, err := domainservice.NewUserDomainSvc(context.TODO()).RegisterUser(givenUser, planPassword)
    So(user, ShouldBeNil)
    So(err, ShouldNotBeNil)
    So(err, ShouldEqual, errcode.ErrUserNameOccupied)
   })
  })
 })
}

在這個測試方法中,我在頂層Convey中嵌套了兩個并列的Convey方法來組織正向和負向的單元測試,之所以不跟上面那個案例一樣寫兩個并列的頂層Convey方法是因為被測方法 RegisterUser 的入參數太難構造,這也正好給大家展示了我們使用Convey設計單元測試的行為路徑時的靈活性。

這里我們提供了兩個測試用例,正向用例中讓 RegisterUser 依賴的Dao方法 CreateUser 返回創建成功的結果,預期 RegisterUser 返回正確的結果。

而負向用例中則讓 CreateUser 返回用戶名在數據庫中已存在時返回的結果,同時預期 RegisterUser 會返回用戶名已被占用的錯誤 errcode.ErrUserNameOccupied 。

最后咱們用 go test -v命令來看看測試運行的效果:

圖片圖片

Controller 的單元測試

到現在為止我們的單元測試實戰案例已經覆蓋了數據訪問Dao層、API對接層和領域服務層。還剩下一個用戶接口層沒有涉及到,即項目的Controller方法該怎么做單元測試呢?

首先我覺得,按照我們項目的分層架構來說Controller是負責接受和驗證請求和調用下層拿到結果返回響應的,在這里包含核心業務邏輯。如果我們能把它依賴的下層的單元測試做到位,Controller的單元測試可以不做。

不過我們知道有個驗證項目質量的數據指標叫:測試覆蓋率,這個指標肯定越高越好,所以這里我在簡單地把Controller 處理函數的單元測試給大家過一下。

在 Web 項目中 Controller 里都是API接口的請求處理函數,為它們編寫單元測試需要用到Go自帶的net/http/httptest包, 它可以mock一個HTTP請求和響應記錄器,讓我們的 server 端接收并處理我們 mock 的HTTP請求,同時使用響應記錄器來記錄 server 端返回的響應內容。

這里我們那用戶登陸這個接口給大家演示它的Controller函數是怎么做單元測試的,它的單元測試如下。

func TestLoginUser(t *testing.T) {
 Convey("Given right login name and password", t, func() {
  loginName := "yourName@go-mall.com"
  password := "12Qa@6783Wxf3~!45"

  Convey("When use them to Login through API /user/login", func() {
   var s *appservice.UserAppSvc
   gomonkey.ApplyMethod(s, "UserLogin", func(_ *appservice.UserAppSvc, _ *request.UserLogin) (*reply.TokenReply, error) {
    LoginReply := &reply.TokenReply{
     AccessToken:   "70624d19b6644b0bbf8169f51fb5a91f132edebc",
     RefreshToken:  "d16e22fef5cb7f6c69355c9a3c6ce8d1d3b37a84",
     Duration:      7200,
     SrvCreateTime: "2025-02-01 15:34:35",
    }
    return LoginReply, nil
   })

   var b bytes.Buffer
   json.NewEncoder(&b).Encode(map[string]string{"login_name": loginName, "password": password})
   req := httptest.NewRequest(http.MethodPost, "/user/login", &b)
   req.Header.Set("platform", "H5")
   gin.SetMode(gin.ReleaseMode) // 不讓它在控制臺里輸出路由信息
   g := gin.New()
   router.RegisterRoutes(g)
   // mock一個響應記錄器
   w := httptest.NewRecorder()
   // 讓server端處理mock請求并記錄返回的響應內容
   g.ServeHTTP(w, req)

   Convey("Then the user will login successfully", func() {
    So(w.Code, ShouldEqual, http.StatusOK)
    // 檢驗響應內容是否復合預期
    var resp map[string]interface{}
    json.Unmarshal([]byte(w.Body.String()), &resp)
    respData := resp["data"].(map[string]interface{})
    So(respData["access_token"], ShouldNotBeEmpty)
   })
  })
 })

在這個單元測試中我們還是會用 goconvey來組織測試的行為路徑,用 gomonkey 給Controller函數調用的應用服務方法做打樁返回Mock結果,不然就跟用POSTMAN 請求接口一樣咧,那樣的話如果下層代碼里有數據庫CURD更新之類操作的話還是會去實際訪問數據庫的,這顯然不是我們想要的。

對于Controller方法的驗證主要聚焦于請求參數的驗證以及響應結果的驗證,因為 Controller 在我們項目的分層設計中就只干這兩件事。

總結

通過這幾節單元測試實戰的內容大家應該能體會到,我們為項目做好分層設計的一個優點--好測試。每個分層都有具體的職責,每塊代碼的邊界不至于過大,這樣我們做單元測試代碼寫起來會更簡單。如果把所有邏輯都耦合在Controller 函數那種代碼,寫單元測試的難度先不說,有效性也很難保證,因為測試的顆粒度太大必然導致很難測出代碼內部的問題。

責任編輯:武曉燕 來源: 網管叨bi叨
相關推薦

2025-04-28 01:55:00

工具sqlmockSQL

2024-12-05 09:13:55

Go項目模塊

2025-05-07 09:06:03

2021-07-28 08:53:53

GoGDB調試

2024-02-21 19:02:05

Go模板化方式

2022-09-27 09:21:34

SOLID開閉原則Go

2023-04-26 00:41:36

A/B測試郵件數量

2022-01-17 07:50:37

Go代碼規范

2023-05-26 00:06:05

2015-06-15 11:45:55

2021-11-29 22:59:34

Go Dockertest集成

2025-03-20 07:01:40

2025-03-28 07:50:00

端到端測試Go語言

2020-09-27 14:00:44

代碼

2021-07-02 17:22:50

前端TDDBDD

2024-02-21 19:56:48

??filterA并發計算

2022-11-09 07:18:18

驅動測試BDD

2022-08-30 09:57:28

項目傳統對象訪問

2022-07-19 08:01:55

函數Go格式化

2016-08-31 09:19:57

點贊
收藏

51CTO技術棧公眾號

六月丁香激情网| 国产精品高潮呻吟久久av无限| 亚洲天堂国产视频| 在线你懂的视频| 99精品欧美一区二区蜜桃免费| 青青在线视频一区二区三区| 黑人と日本人の交わりビデオ| 亚洲精品第一| 午夜精品视频在线观看| 欧洲亚洲一区二区| 国产福利第一视频| 国产精品视频| 欧美巨乳在线观看| 欧美多人猛交狂配| 一本一道久久a久久| 色综合天天综合网国产成人综合天| 亚洲免费久久| 天堂成人在线观看| 激情成人午夜视频| 热久久这里只有精品| 亚洲一级生活片| 国产亚洲第一伦理第一区| 日韩欧美国产午夜精品| 中文字幕在线观看第三页| 狂野欧美性猛交xxxxx视频| 国产午夜精品理论片a级大结局| 亚洲精品免费av| 亚洲毛片一区二区三区| 精品成人久久| 欧美大尺度在线观看| 亚洲AV无码成人精品区明星换面| jizz性欧美23| 3d动漫精品啪啪一区二区竹菊 | 成人激情开心网| 精品久久久久久无| 日韩中文字幕a| 国产日韩电影| 亚洲v中文字幕| 欧美大片免费播放| 91高清在线| 久久久久久久综合| 国产一区二区三区免费不卡| 99热这里只有精品99| 青青草国产精品97视觉盛宴| 日韩av片电影专区| 偷偷操不一样的久久| 红桃视频欧美| 欧美日韩国产999| 欧美激情精品久久久久久免费| 国产一区二区区别| 亚洲天堂男人天堂| 亚洲精品午夜视频| 精品盗摄女厕tp美女嘘嘘| 亚洲美女在线视频| av在线网站观看| 欧美一区 二区| 亚洲国产精品va在线看黑人| 无码人妻aⅴ一区二区三区玉蒲团| 99精品视频在线免费播放| 欧美日韩亚洲综合在线| 亚洲欧美久久久久| 日韩深夜福利网站| 91精品国产欧美一区二区18| 欧美第一页浮力影院| 国产精品久久久久久吹潮| 91国偷自产一区二区开放时间| 国产综合免费视频| 美女日韩欧美| 91久久线看在观草草青青| 欧美黄色一级片视频| 欧美激情20| 日本精品视频一区二区| 亚洲色图久久久| 亚洲爽爆av| 欧美一级片在线观看| 白丝校花扒腿让我c| 激情av综合| 亚洲视频专区在线| 你懂得在线观看| 亚洲精品一区二区在线看| 欧美理论电影在线观看| 欧美亚洲天堂网| 午夜影院日韩| 国产美女91呻吟求| 国产三级按摩推拿按摩| 懂色av中文一区二区三区| 国产伦精品一区二区三区视频孕妇 | 一区二区三区av电影| 蜜臀精品一区二区| 特黄毛片在线观看| 欧美三区在线观看| 无码人妻一区二区三区精品视频| 久久97久久97精品免视看秋霞| 精品中文视频在线| 四虎影视一区二区| 在线观看亚洲| 国产成人精品免费久久久久| 91麻豆国产视频| 成人午夜伦理影院| 日韩在线三区| 青草视频在线免费直播| 好吊成人免视频| 999在线精品视频| 午夜精品影视国产一区在线麻豆| 最好看的2019年中文视频| 免费一级a毛片夜夜看| 欧美在线综合| 99国产在线视频| 国产二区视频在线观看| 亚洲免费观看高清| 99热手机在线| 卡通动漫国产精品| www.亚洲天堂| 波多野结衣视频网站| 精彩视频一区二区三区| 欧美日韩三区四区| 国产美女一区视频| 欧美久久免费观看| 精品少妇人妻一区二区黑料社区| 亚洲女同中文字幕| 国产精品v片在线观看不卡| 亚洲免费黄色片| 国产精品美女久久久久久久久久久| 97视频在线免费| 国产激情精品一区二区三区| 亚洲视频一区二区三区| 日韩精品无码一区二区| 韩国女主播成人在线| 日本福利一区二区三区| 高清在线视频不卡| 日韩视频国产视频| 少妇太紧太爽又黄又硬又爽小说| 雨宫琴音一区二区在线| 91日韩在线播放| 永久免费av在线| 色婷婷综合激情| 特级西西人体wwwww| 欧美激情1区2区3区| 成人激情视频网| www免费网站在线观看| 欧美日韩在线免费观看| 这里只有精品在线观看视频 | 青青草av在线播放| 成人一区二区三区视频在线观看| 国产手机视频在线观看| 久久亚洲资源中文字| 亚洲视频在线视频| 精产国品一区二区| 久久久国产一区二区三区四区小说| 丰满少妇久久久| 国产 日韩 欧美 综合 一区| 九九热r在线视频精品| 国产av一区二区三区精品| 亚洲视频免费在线观看| 一区二区久久精品| 性欧美69xoxoxoxo| 91沈先生在线观看| 国产一区久久精品| 日韩欧美一区二区视频| 九九久久免费视频| 成人午夜短视频| 国产婷婷一区二区三区| 欧美顶级毛片在线播放| 91成人性视频| 香蕉视频911| 色综合久久综合中文综合网| 99热亚洲精品| 国产三级精品三级在线观看| 国产一区二区不卡| 成人免费看片视频在线观看| 日韩成人在线看| 欧美激情高清视频| 亚洲v在线观看| 天天久久夜夜| 国产999在线观看| 福利片在线观看| 欧美网站一区二区| 色哟哟一一国产精品| 久久99国产精品麻豆| 欧美三级午夜理伦三级老人| 91欧美极品| 91黄色8090| 免费毛片在线| 欧美午夜一区二区三区| 国产精品视频一区二区在线观看| 国产一区二区h| 男女日批视频在线观看| 免费一区二区| 国产日韩在线观看av| 18av在线播放| 日韩av最新在线| 亚洲视屏在线观看| 一区二区三区在线看| 爱爱免费小视频| 黑人巨大精品欧美黑白配亚洲| 国产91沈先生在线播放| 九一国产精品| 亚洲综合日韩在线| 亚洲一二三四| 美女视频黄免费的亚洲男人天堂| 蜜桃av中文字幕| 欧美在线你懂得| 久久免费播放视频| 国产婷婷色一区二区三区| 午夜诱惑痒痒网| 久久精品麻豆| av在线免费观看国产| 狠狠做深爱婷婷综合一区| 亚洲一区二区自拍| 欧美二三四区| 欧美激情综合色综合啪啪五月| 国产特黄在线| 欧美r级电影在线观看| 91丨九色丨海角社区| 亚洲一区二区偷拍精品| 男人的天堂官网| 成人久久18免费网站麻豆| 污污的视频免费| 美日韩精品视频| 国产激情在线看| 黑人操亚洲人| 久久久一本精品99久久精品66| 精品三级国产| 国产精品直播网红| 蜜臀国产一区| 韩国精品久久久999| av在线免费网站| 最新国产成人av网站网址麻豆| 五月激情婷婷综合| 欧美一区二区免费观在线| 亚洲永久精品一区| 欧美日韩国产精品| 国产精品成人网站| 亚洲精品欧美二区三区中文字幕| 三上悠亚ssⅰn939无码播放 | 国产乱人伦真实精品视频| 麻豆蜜桃在线观看| 久久久久久久香蕉网| 最新av在线播放| 麻豆国产va免费精品高清在线| 福利在线视频导航| 亚洲三级av在线| 国内视频一区二区| 捆绑调教日本一区二区三区| 欧美男插女视频| 搞黄网站在线观看| 色婷婷综合成人av| 成人p站proumb入口| 亚洲视频一区二区三区| 国产黄在线播放| 亚洲欧美制服综合另类| 日本成人一区二区三区| 日韩精品免费在线| 污视频网站免费观看| 亚洲精品99久久久久中文字幕| 亚洲精品字幕在线| 欧美电视剧在线看免费| 亚洲av无码国产精品永久一区| 欧美一区二区大片| 国产sm主人调教女m视频| 日韩欧美成人激情| 欧美熟妇交换久久久久久分类| 欧美xxxxx牲另类人与| 亚洲国产日韩在线观看| 精品国精品自拍自在线| 五月激情婷婷综合| 亚洲人成自拍网站| 在线看免费av| 久久久精品国产亚洲| 97caopor国产在线视频| 欧美极品xxxx| 亚洲十八**毛片| 国产成人精品一区二区| 成人在线免费电影网站| 成人综合网网址| 国产精品网站在线看| 精品一区久久久久久| 欧美人与物videos另类xxxxx| 秋霞毛片久久久久久久久| 欧美丝袜丝交足nylons172| 天天干天天操天天干天天操| 国产一区清纯| 国产无套内射久久久国产| 日本伊人色综合网| 久久无码人妻一区二区三区| 99视频精品在线| av永久免费观看| 亚洲精品国产成人久久av盗摄| 青青草精品在线视频| 精品欧美激情精品一区| 中文字幕+乱码+中文字幕明步| 91精品国产综合久久精品app| 六月丁香综合网| 亚洲图片欧美日产| 久做在线视频免费观看| 欧美日韩国产成人在线| 色综合桃花网| 91视频-88av| 最新精品国偷自产在线| 欧美日韩亚洲国产成人| 亚洲综合丁香| 亚洲综合伊人久久| 久久一二三国产| 在线观看天堂av| av久久网站| 不卡一区二区三区视频| 欧美综合另类| 夜夜添无码一区二区三区| 日本不卡一区二区| 伦理片一区二区| 国产精品久久久久天堂| 国产午夜小视频| 欧美男女性生活在线直播观看| 人妻少妇精品无码专区| 精品国产一区二区三区四区在线观看 | 一本综合精品| 在线观看av免费观看| 91美女在线视频| 国产av 一区二区三区| 日本大香伊一区二区三区| 国产成人自拍一区| 久久精品一区中文字幕| 99久久er| 蜜桃传媒一区二区| 在线日韩中文| 久久久九九九热| 中文字幕不卡的av| 在线观看日韩中文字幕| 精品国产百合女同互慰| 黄色网在线免费看| 国产精品久久久| 自拍亚洲一区| 精品视频免费在线播放| 国产成人欧美日韩在线电影| 美国黄色片视频| 欧美三级中文字幕| 搞黄视频在线观看| 欧美孕妇孕交黑巨大网站| 国产精品久久久网站| 国产乱子伦精品无码专区| 麻豆精品在线视频| 日本黄色小视频在线观看| 欧美日韩一区二区在线播放| 天天操天天射天天| 国内精品久久久久影院优| 91麻豆精品激情在线观看最新| 国产乱子伦精品视频| 国产成人在线视频网站| 青草影院在线观看| 欧美一级在线视频| а√天堂资源地址在线下载| 成人黄色短视频在线观看| 婷婷亚洲综合| 国产美女18xxxx免费视频| 国产精品国产三级国产普通话99| 中日韩av在线| 综合激情国产一区| 青青久久精品| 国产又大又长又粗又黄| 精品一区二区三区在线观看国产| 欧美国产日韩在线观看成人 | 69久久夜色精品国产69| 好吊妞视频这里有精品 | 久久香蕉精品| 中文字幕免费在线看线人动作大片| 色婷婷久久久亚洲一区二区三区| 男女网站在线观看| 国产精品免费一区二区三区都可以| 成人中文在线| 看看黄色一级片| 玉米视频成人免费看| 手机看片福利永久| 欧美在线播放视频| 欧美三级美国一级| 999久久久精品视频| 一区二区三区加勒比av| 天天操天天操天天干| 国产国语videosex另类| 国产精品久久占久久| wwwww在线观看| 欧美午夜女人视频在线| av女优在线| 97在线电影| 午夜在线一区二区| 黄色av片三级三级三级免费看| 欧美一区二区在线看| 极品av在线| 亚洲欧美成人一区| 国产馆精品极品| 日本中文在线播放| 日韩在线视频免费观看| 99ri日韩精品视频| 黑人粗进入欧美aaaaa| 亚洲精品视频自拍| 全色精品综合影院| 亚洲精品免费在线视频| 亚洲女人av| 欧美成人一区二区三区高清| 国产视频丨精品|在线观看| 小说区图片区亚洲|