成人性生交大片免费看视频r_亚洲综合极品香蕉久久网_在线视频免费观看一区_亚洲精品亚洲人成人网在线播放_国产精品毛片av_久久久久国产精品www_亚洲国产一区二区三区在线播_日韩一区二区三区四区区区_亚洲精品国产无套在线观_国产免费www

主頁 > 知識庫 > Go語言Mock使用基本指南詳解

Go語言Mock使用基本指南詳解

熱門標簽:烏魯木齊人工電銷機器人系統(tǒng) 濮陽自動外呼系統(tǒng)代理 長沙ai機器人電銷 地圖標注測試 澳門防封電銷卡 智能電銷機器人營銷 賺地圖標注的錢犯法嗎 廣東語音外呼系統(tǒng)供應(yīng)商 福州鐵通自動外呼系統(tǒng)

當前的實踐中問題

在項目之間依賴的時候我們往往可以通過mock一個接口的實現(xiàn),以一種比較簡潔、獨立的方式,來進行測試。但是在mock使用的過程中,因為大家的風(fēng)格不統(tǒng)一,而且很多使用minimal implement的方式來進行mock,這就導(dǎo)致了通過mock出的實現(xiàn)各個函數(shù)的返回值往往是靜態(tài)的,就無法讓caller根據(jù)返回值進行的一些復(fù)雜邏輯。

首先來舉一個例子

package task

type Task interface {
 Do(int) (string, error)
}

通過minimal implement的方式來進行手動的mock

package mock

type MinimalTask struct {
 // filed
}

func NewMinimalTask() *MinimalTask {
 return MinimalTask{}
}

func (mt *MinimalTask) Do(idx int) (string, error) {
 return "", nil
}

在其他包使用Mock出的實現(xiàn)的過程中,就會給測試帶來一些問題。

舉個例子,假如我們有如下的接口定義與函數(shù)定義

package pool

import "github.com/ultramesh/mock-example/task"

type TaskPool interface {
 Run(times int) error
}

type NewTask func() task.Task

我們基于接口定義和接口構(gòu)造函數(shù)定義,封裝了一個實現(xiàn)

package pool

import (
 "fmt"
 "github.com/pkg/errors"
 "github.com/ultramesh/mock-example/task"
)

type TaskPoolImpl struct {
 pool []task.Task
}

func NewTaskPoolImpl(newTask NewTask, size int) *TaskPoolImpl {
 tp := TaskPoolImpl{
  pool: make([]task.Task, size),
 }
 for i := 0; i  size; i++ {
  tp.pool[i] = newTask()
 }
 return tp
}

func (tp *TaskPoolImpl) Run(times int) error {
 poolLen := len(tp.pool)
 for i := 0; i  times; i++ {
  ret, err := tp.pool[i%poolLen].Do(i)
  if err != nil {
   // process error
   return errors.Wrap(err, fmt.Sprintf("error while run task %d", i%poolLen))
  }
  switch ret {
  case "":
   // process 0
   fmt.Println(ret)
  case "a":
   // process 1
   fmt.Println(ret)
  case "b":
   // process 2
   fmt.Println(ret)
  case "c":
   // process 3
   fmt.Println(ret)
  }
 }
 return nil
}

接著我們來寫測試的話應(yīng)該是下面

package pool

import (
 "github.com/golang/mock/gomock"
 "github.com/stretchr/testify/assert"
 "github.com/ultramesh/mock-example/mock"
 "github.com/ultramesh/mock-example/task"
 "testing"
)

type TestSuit struct {
 name string
 newTask NewTask
 size int
 times int
}

func TestTaskPoolRunImpl(t *testing.T) {

 testSuits := []TestSuit{
  {
   nam
  e: "minimal task pool",
   newTask: func() task.Task { return mock.NewMinimalTask() },
   size: 100,
   times: 200,
  },
 }

 for _, suit := range testSuits {
  t.Run(suit.name, func(t *testing.T) {
   var taskPool TaskPool = NewTaskPoolImpl(suit.newTask, suit.size)
   err := taskPool.Run(suit.size)
   assert.NoError(t, err)
  })
 }
}

這樣通過go test自帶的覆蓋率測試我們能看到TaskPoolImpl實際被測試到的路徑為

可以看到的手動實現(xiàn)MinimalTask的問題在于,由于對于caller來說,callee的返回值是不可控的,我們只能覆蓋到由MinimalTask所定死的返回值的路徑,此外mock在我們的實踐中往往由被依賴的項目來操作,他不知道caller怎樣根據(jù)返回值進行處理,沒有辦法封裝出一個簡單、夠用的最小實現(xiàn)供接口測試使用,因此我們需要改進我們mock策略,使用golang官方的mock工具——gomock來進行更好地接口測試。

gomock實踐

我們使用golang官方的mock工具的優(yōu)勢在于

  • 我們可以基于工具生成的mock代碼,我們可以用一種更精簡的方式,封裝出一個minimal implement,完成和手工實現(xiàn)一個minimal implement一樣的效果。
  • 可以允許caller自己靈活地、有選擇地控制自己需要用到的那些接口方法的入?yún)⒁约俺鰠ⅰ?/li>

還是上面TaskPool的例子,我們現(xiàn)在使用gomock提供的工具來自動生成一個mock Task

mockgen -destination mock/mock_task.go -package mock -source task/interface.go

在mock包中生成一個mock_task.go來實現(xiàn)接口Task

首先基于mock_task.go,我們可以實現(xiàn)一個MockMinimalTask用于最簡單的測試

package mock

import "github.com/golang/mock/gomock"

func NewMockMinimalTask(ctrl *gomock.Controller) *MockTask {
 mock := NewMockTask(ctrl)
 mock.EXPECT().Do().Return("", nil).AnyTimes()
 return mock
}

于是這樣我們就可以實現(xiàn)一個MockMinimalTask用來做一些測試

package pool

import (
 "github.com/golang/mock/gomock"
 "github.com/stretchr/testify/assert"
 "github.com/ultramesh/mock-example/mock"
 "github.com/ultramesh/mock-example/task"
 "testing"
)

type TestSuit struct {
 name string
 newTask NewTask
 size int
 times int
}

func TestTaskPoolRunImpl(t *testing.T) {

 testSuits := []TestSuit{
  //{
  // name: "minimal task pool",
  // newTask: func() task.Task { return mock.NewMinimalTask() },
  // size: 100,
  // times: 200,
  //},
 {
   name: "mock minimal task pool",
   newTask: func() task.Task { return mock.NewMockMinimalTask(ctrl) },
   size: 100,
   times: 200,
  },
 }

 for _, suit := range testSuits {
  t.Run(suit.name, func(t *testing.T) {
   var taskPool TaskPool = NewTaskPoolImpl(suit.newTask, suit.size)
   err := taskPool.Run(suit.size)
   assert.NoError(t, err)
  })
 }
}

我們使用這個新的測試文件進行覆蓋率測試

可以看到測試結(jié)果是一樣的,那當我們想要達到更高的測試覆蓋率的時候應(yīng)該怎么辦呢?我們進一步修改測試

package pool

import (
 "errors"
 "github.com/golang/mock/gomock"
 "github.com/stretchr/testify/assert"
 "github.com/ultramesh/mock-example/mock"
 "github.com/ultramesh/mock-example/task"
 "testing"
)

type TestSuit struct {
 name string
 newTask NewTask
 size int
 times int
 isErr bool
}

func TestTaskPoolRunImpl_MinimalTask(t *testing.T) {

 ctrl := gomock.NewController(t)
 defer ctrl.Finish()

 testSuits := []TestSuit{
  //{
  // name: "minimal task pool",
  // newTask: func() task.Task { return mock.NewMinimalTask() },
  // size: 100,
  // times: 200,
  //},
  {
   name: "mock minimal task pool",
   newTask: func() task.Task { return mock.NewMockMinimalTask(ctrl) },
   size: 100,
   times: 200,
  },
  {
   name: "return err",
   newTask: func() task.Task {
    mockTask := mock.NewMockTask(ctrl)
  // 加入了返回錯誤的邏輯
    mockTask.EXPECT().Do(gomock.Any()).Return("", errors.New("return err")).AnyTimes()
    return mockTask
   },
   size: 100,
   times: 200,
   isErr: true,
  },
 }

 for _, suit := range testSuits {
  t.Run(suit.name, func(t *testing.T) {
   var taskPool TaskPool = NewTaskPoolImpl(suit.newTask, suit.size)
   err := taskPool.Run(suit.size)
   if suit.isErr {
    assert.Error(t, err)
   } else {
    assert.NoError(t, err)
   }
  })
 }
}

這樣我們就能夠覆蓋到error的處理邏輯

甚至我們可以更trick的方式來將所有語句都覆蓋到,代碼中的testSuits改成下面這樣

package pool

import (
 "errors"
 "github.com/golang/mock/gomock"
 "github.com/stretchr/testify/assert"
 "github.com/ultramesh/mock-example/mock"
 "github.com/ultramesh/mock-example/task"
 "testing"
)

type TestSuit struct {
 name string
 newTask NewTask
 size int
 times int
 isErr bool
}

func TestTaskPoolRunImpl_MinimalTask(t *testing.T) {

 ctrl := gomock.NewController(t)
 defer ctrl.Finish()

 strs := []string{"a", "b", "c"}
 count := 0
 size := 3
 rounds := 1

 testSuits := []TestSuit{
  //{
  // name: "minimal task pool",
  // newTask: func() task.Task { return mock.NewMinimalTask() },
  // size: 100,
  // times: 200,
  //},
  {
   name: "mock minimal task pool",
   newTask: func() task.Task { return mock.NewMockMinimalTask(ctrl) },
   size: 100,
   times: 200,
  },
  {
   name: "return err",
   newTask: func() task.Task {
    mockTask := mock.NewMockTask(ctrl)
    mockTask.EXPECT().Do(gomock.Any()).Return("", errors.New("return err")).AnyTimes()
    return mockTask
   },
   size: 100,
   times: 200,
   isErr: true,
  },
  {
   name: "check input and output",
   newTask: func() task.Task {
    mockTask := mock.NewMockTask(ctrl)
  // 這里我們通過Do的設(shè)置檢查了mackTask.Do調(diào)用時候的入?yún)⒁约罢{(diào)用次數(shù)
  // 通過Return來設(shè)置發(fā)生調(diào)用時的返回值
    mockTask.EXPECT().Do(count).Return(strs[count%3], nil).Times(rounds)
    count++
    return mockTask
   },
   size: size,
   times: size * rounds,
   isErr: false,
  },
 }
 var taskPool TaskPool
 for _, suit := range testSuits {
  t.Run(suit.name, func(t *testing.T) {
   taskPool = NewTaskPoolImpl(suit.newTask, suit.size)
   err := taskPool.Run(suit.times)
   if suit.isErr {
    assert.Error(t, err)
   } else {
    assert.NoError(t, err)
   }

  })
 }
}

這樣我們就可以覆蓋到所有語句

思考Mock的意義

之前和一些同學(xué)討論過,我們?yōu)槭裁匆褂胢ock這個問題,發(fā)現(xiàn)很多同學(xué)的覺得寫mock的是約定好接口,然后在面向接口做開發(fā)的時候能夠方便測試,因為不需要接口實際的實現(xiàn),而是依賴mock的Minimal Implement就可以進行單元測試。我認為這是對的,但是同時也覺得mock的意義不僅僅是如此。

在我看來,面向接口開發(fā)的實踐中,你應(yīng)該時刻對接口的輸入和輸出保持敏感,更進一步的說,在進行單元測試的時候,你需要知道在給定的用例、輸入下,你的包會對起使用的接口方法輸入什么,調(diào)用幾次,然后返回值可能是什么,什么樣的返回值對你有影響,如果你對這些不了解,那么我覺得或者你應(yīng)該去做更多地嘗試和了解,這樣才能盡可能通過mock設(shè)計出更多的單測用例,做更多且謹慎的檢查,提高測試代碼的覆蓋率,確保模塊功能的完備性。

Mock與設(shè)計模式

mock與單例

客觀來講,借助go語言官方提供的同步原語sync.Once,實現(xiàn)單例、使用單例是很容易的事情。在使用單例實現(xiàn)的過程中,單例的調(diào)用者往往邏輯中依賴提供的get方法在需要的時候獲取單例,而不會在自身的數(shù)據(jù)結(jié)構(gòu)中保存單例的句柄,這也就導(dǎo)致我們很難類比前面介紹的case,使用mock進行單元測試,因為caller沒有辦法控制通過get方法獲取的單例。

既然是因為沒有辦法更改單例返回,那么解決這個問題最簡單的方式就是我們就應(yīng)改提供一個set方法來設(shè)置更改單例。假設(shè)我們需要基于上面的case實現(xiàn)一個單例的TaskPool。假設(shè)我們定義了PoolImpl實現(xiàn)了Pool的接口,在創(chuàng)建單例的時候我們可能是這么做的(為了方便說明,這里我們用最早手工寫的基于MinimalTask來寫TaskPool的單例)

package pool

import (
 "github.com/ultramesh/mock-example/mock"
 "github.com/ultramesh/mock-example/task"
 "sync"
)

var once sync.Once
var p TaskPool

func GetTaskPool() TaskPool{
 once.Do(func(){
  p = NewTaskPoolImpl(func() task.Task {return mock.NewMinimalTask()},10)
 })
 return p
}

這個時候問題就來了,假設(shè)某個依賴于TaskPool的模塊中有這么一段邏輯

package runner

import (
 "fmt"
 "github.com/pkg/errors"
 "github.com/ultramesh/mock-example/pool"
)

func Run(times int) error {
 // do something
 fmt.Println("do something")

 // call pool
 p := pool.GetTaskPool()
 err := p.Run(times)
 if err != nil {
  return errors.Wrap(err, "task pool run error")
 }

 // do something
 fmt.Println("do something")
 return nil
}

那么這個Run函數(shù)的單測應(yīng)該怎么寫呢?這里的例子還比較簡單,要是TaskPool的實現(xiàn)還要依賴一些外部配置文件,實際情形就會更加復(fù)雜,當然我們在這里不討論這個情況,就是舉一個簡單的例子。在這種情況下,如果單例僅僅只提供了get方法的話是很難進行解耦測試的,如果使用GetTaskPool勢必會給測試引入不必要的復(fù)雜性,我們還需要提供一個單例的實現(xiàn)者提供一個set方法來解決單元測試解耦的問題。將單例的實現(xiàn)改成下面這樣,對外暴露一個單例的set方法,那么我們就可以通過set方法來進行mock。

import (
 "github.com/ultramesh/mock-example/mock"
 "github.com/ultramesh/mock-example/task"
 "sync"
)

var once sync.Once
var p TaskPool

func SetTaskPool(tp TaskPool) {
 p = tp
}

func GetTaskPool() TaskPool {
 once.Do(func(){
  if p != nil {
   p = NewTaskPoolImpl(func() task.Task {return mock.NewMinimalTask()},10)
  }
  
 })
 return p
}

使用mockgen生成一個MockTaskPool實現(xiàn)

mockgen -destination mock/mock_task_pool.go -package mock -source pool/interface.go

類似的,基于前面介紹的思想我們基于自動生成的代碼實現(xiàn)一個MockMinimalTaskPool

package mock

import "github.com/golang/mock/gomock"

func NewMockMinimalTaskPool(ctrl *gomock.Controller) *MockTaskPool {
 mock := NewMockTaskPool(ctrl)
 mock.EXPECT().Run(gomock.Any()).Return(nil).AnyTimes()
 return mock
}

基于MockMinimalTaskPool和單例暴露出的set方法,我們就可以將TaskPool實現(xiàn)的邏輯拆除,在單測中只測試自己的代碼

package runner

import (
 "github.com/golang/mock/gomock"
 "github.com/stretchr/testify/assert"
 "github.com/ultramesh/mock-example/mock"
 "github.com/ultramesh/mock-example/pool"
 "testing"
)

func TestRun(t *testing.T) {

 ctrl := gomock.NewController(t)
 defer ctrl.Finish()

 p := mock.NewMockMinimalTaskPool(ctrl)

 pool.SetTaskPool(p)

 err := Run(100)
 assert.NoError(t, err)
}

到此這篇關(guān)于Go語言Mock使用基本指南詳解的文章就介紹到這了,更多相關(guān)Go語言Mock使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • 用gomock進行mock測試的方法示例
  • 使用Gomock進行單元測試的方法示例

標簽:廣西 德州 調(diào)研邀請 阿克蘇 西雙版納 貴陽 太原 慶陽

巨人網(wǎng)絡(luò)通訊聲明:本文標題《Go語言Mock使用基本指南詳解》,本文關(guān)鍵詞  語言,Mock,使用,基本,指南,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《Go語言Mock使用基本指南詳解》相關(guān)的同類信息!
  • 本頁收集關(guān)于Go語言Mock使用基本指南詳解的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    亚洲激情啪啪| 青青影院一区二区三区四区| 污视频网站在线观看| av视屏在线播放| 黄色片视频在线播放| 亚洲美女久久精品| 国产成人麻豆精品午夜在线| 亚洲天堂一区二区三区四区| 狠狠色丁香久久婷婷综合丁香| 日本在线免费观看视频| 亚洲国产精品中文| 日韩欧美国产另类| 亚洲国产欧美一区| 中文精品无码中文字幕无码专区| 国产精品成人观看视频国产奇米| 美女啪啪无遮挡| 成人黄色激情视频| 婷婷综合久久中文字幕蜜桃三电影| 99精品视频国产| 你懂的在线观看视频网站| 二人午夜免费观看在线视频| 波多野结衣家庭教师在线观看| 麻豆传传媒久久久爱| 久久999免费视频| 亚洲久久中文字幕| 国产激情一区二区三区| 亚洲精品一线二线三线无人区| 国产精品嫩草影院久久久| 色中色综合影院手机版在线观看| 亚洲国产精品人久久电影| 精品卡1卡2卡三卡免费网站| 色欧美片视频在线观看| 亚洲香蕉伊在人在线观| 一区二区三区四区国产精品| 色多多视频网站| 成人h动漫免费观看网站| 清纯唯美亚洲经典中文字幕| 精品国产乱码久久久久酒店| 国产美女一区视频| 日本亚洲精品在线观看| 麻豆网站在线免费观看| 日韩国产欧美一区二区三区| 一级黄色在线视频| 无码无套少妇毛多18pxxxx| 国产精品对白| 中国极品少妇videossexhd| 少妇激情av一区二区| 精品剧情v国产在线观看在线| jvid福利在线一区二区| 欧美色图在线播放| 成年大片免费视频播放二级| 欧美成人777| 国产精品素人一区二区| 另类图片激情| 日韩中文字幕二区| 一本久久a久久免费精品不卡| 国产无遮挡又黄又爽免费软件| 国产精品九九| 日韩av中文字幕第一页| 香港三级日本三级a视频| 高清精品视频| www.天天射| 欧美疯狂性受xxxxx喷水图片| 狠狠操狠狠干视频| 青青在线视频观看| 狠狠操夜夜操| 亚洲精品成人无码毛片| 国产偷倩在线播放| 成人全视频在线观看在线播放高清| 欧美一区=区三区| 国产一区二区三区三区在线观看| 成人午夜精品在线| 欧美日韩激情一区| 男女羞羞视频在线观看| 五月伊人六月| 黄色国产在线视频| 欧美精品电影| 久草视频国产在线| 天堂视频免费在线观看| 日本免费高清一区| 老牛影视精品| 在线观看污网站| 亚洲国产综合91精品麻豆| 久草国产精品视频| 老司机2019福利精品视频导航| 在线免费色视频| 在线观看中文字幕| 欧美日韩国产丝袜另类| 久久精品国产99久久99久久久| 欧美一级二级三级蜜桃| 亚洲丁香日韩| 九九热精品在线| 日本午夜精品理论片a级app发布| 99久re热视频这里只有精品6| 久久中文视频| 3d性欧美动漫精品xxxx软件| 久久国产精品一区二区| 精品国产亚洲一区二区三区大结局| 欧美激情伊人电影| 亚洲男女毛片无遮挡| 成人在线丰满少妇av| 亚洲欧美日韩国产另类专区| 青青草原国产视频| 女人十八岁毛片| 亚洲第一论坛sis| 公侵犯人妻一区二区三区| 欧美极品jizzhd欧美18| 亚洲av成人片无码| 亚洲一区电影777| 色综合欧美在线| 久久国产精品色av免费看| 欧美精品aⅴ在线视频| 欧美最猛性xxxxx亚洲精品| 成人性生交大片免费观看嘿嘿视频| 日本欧美色图| 国产成人综合av| 国产手机免费视频| 国产精品13p| 日韩在线免费视频观看| 男女h黄动漫啪啪无遮挡软件| 国产精品美女久久久久aⅴ国产馆| 精品国产鲁一鲁一区二区张丽| 亚欧精品在线| 国产自产自拍视频在线观看| 国产精品成人一区二区网站软件| 国产精品久久福利| 欧美日韩在线精品一区二区三区激情| 人妻 日韩 欧美 综合 制服| 日韩1区2区3区| 五月国产精品| 伊人久久噜噜噜躁狠狠躁| 国产三级精品在线观看| 国产精品久久久久久久久婷婷| 国产在线一区二区三区播放| 在线视频中文字幕久| 国产欧美一区二区精品婷婷| 日韩高清有码在线| 综合图区欧美| 99riav国产精品视频| 日韩动漫在线观看| 人妻精品一区二区三区| 亚洲精品极品少妇16p| 亚洲精品影院在线观看| 免费观看黄色大片| 国产精品一区久久久久| 91麻豆国产视频| 国产传媒日韩欧美成人| 91在线免费网站| 国产91在线高潮白浆在线观看| 欧美禁忌电影| 国产电影精品久久禁18| 亚洲911精品成人18网站| 欧美**字幕| 一区二区三区美女视频| 亚洲国产中文在线二区三区免| 浮力国产第一页| 欧美日韩另类国产亚洲欧美一级| 国产黄在线免费观看| 欧美激情影音先锋| 风流少妇一区二区三区91| 亚洲国语精品自产拍在线观看| 99在线|亚洲一区二区| 午夜精品一区二区三区视频免费看| 国产精品天天摸av网| 国产精品一站二站| 亚洲欧美日韩一二三区| 黄色免费网址大全| 国产精品一区二区三区网站| 无套内谢大学处破女www小说| 岛国片免费观看| 尤物视频在线观看免费| 麻豆短视频在线观看| 国产999精品久久久影片官网| 久草视频免费看| 亚洲日本韩国在线| 日韩一区二区视频在线观看| 亚洲激情丁香| 毛片在线网址| 国产精品mv在线观看| 欧美成人手机视频| 国产呦精品一区二区三区网站| 精品久久久久久中文字幕一区奶水| 欧美一区激情视频在线观看| 免费xxxx性欧美18vr| 国产毛片久久久久久国产毛片| 欧美精品制服第一页| 亚洲精品久久久久久久久久久久| 日本边添边摸边做边爱的第三级| 亚洲国产精品自拍| 欧美一区二区三区爽爽爽| 国产精品乱战久久久| 在线观看日批视频| 亚洲综合成人婷婷小说| 忘忧草在线日韩www影院| 天堂av免费在线| 尤物视频免费| 国产丝袜在线播放| 国产精品高清一区二区三区| 人人妻人人澡人人爽| 野花视频免费在线观看| 欧美精品久久久久性色| 无套内谢的新婚少妇国语播放| 中文字幕亚洲不卡| 欧美虐宫另类残忍视频| 黄色av小说在线观看| 欧美精品与人动性物交免费看| 日韩黄色一级片| 午夜色香蕉导航| 欧美a在线观看| 精品一区二区6| 色噜噜日韩精品欧美一区二区| 亚洲精品资源| 精品国产一区a| 国产精品一线二线三线| 亚洲国产欧美一区二区三区丁香婷| 97热在线精品视频在线观看| 国产精品免费看久久久香蕉| 国产精品99久久久久久董美香| 国产美女视频91| 丁香一区二区三区| 亚洲奶汁xxxx哺乳期| 色婷婷av一区二区三区丝袜美腿| 欧美一区二区三区在线播放| 国产日本一区二区三区| 亚洲视频一区二区免费在线观看| 另类国产精品一区二区| 日本中文字幕电影| 男人天堂影院| 99一区二区三区| 一级日韩一级欧美| 国产一区二区久久精品| 波多野结衣先锋影音| 欧美性大战久久久久久久蜜臀| 91精品丝袜国产高跟在线| 波多野结衣在线观看一区| 韩剧1988在线观看免费完整版| 国产精品视频a| 日本久久中文字幕| 91精彩视频在线播放| 内射无码专区久久亚洲| 国产一区二区在线免费| 免费av在线网址| 美女精品自拍一二三四| 97se亚洲国产综合自在线不卡| 亚洲经典视频在线观看| 成年人在线观看| 2021av网| www.-级毛片线天内射视视| 欧美日韩国产精品一区二区不卡中文| 久久精品视频免费看| 亚洲成人第一页| 91精品福利视频| 亚洲国产欧美日韩| 91精品蜜臀一区二区三区在线| 国产婷婷色综合av蜜臀av| 国产精品丝袜久久久久久app| 制服丝袜中文字幕在线观看| 亚洲一卡二卡在线| 一区二区视频在线观看免费的| 免费看一区二区三区| 亚洲午夜电影在线观看| 国产伦精品一区二区三区视频青涩| 日本黄色免费视频| 国产精品偷伦视频免费观看了| 欧美日韩国产综合一区二区三区| 国产自产高清不卡| 亚洲精品成人久久久998| 国产美女无遮挡永久免费| 黄网站在线观看高清免费| 深田咏美在线x99av| www.成人免费视频| 91精品在线国产| 波多野结衣视频免费观看| 日韩中文字幕视频在线| 亚洲欧美视频二区| 亚洲欧美制服综合另类| 50路60路老熟妇啪啪| 欧美成人欧美edvon| 国产免费区一区二区三视频免费| 亚洲视频在线观看不卡| 国产成人99久久亚洲综合精品| 男女激烈动态图| 久久久久久久久久影院| 亚洲国产精品人人爽夜夜爽| 精品人妻一区二区三区日产乱码卜| 女人18毛片九区毛片在线| 色呦呦免费观看| 久操av在线| 无码国产精品96久久久久| 激情亚洲网站| 97久久精品人人爽人人爽蜜臀| 激情综合激情| 中文字幕有码视频| 一级理论片在线观看| www.成人在线观看| 亚洲精品无码久久久| 久久久精品国产一区二区三区| 99热最新网址| 国产黄色免费网站| 人妻少妇无码精品视频区| 久久99国产精品99久久| 四季av中文字幕| 亚洲**2019国产| 丁香另类激情小说| 蜜桃视频在线入口www| 成人在线免费在线观看| 深夜福利在线看| 国产第一页在线播放| 中文精品电影| 全部a∨一极品视觉盛宴| 国产卡二和卡三的视频| 深夜福利在线观看直播| jizzjizz欧美69巨大| 一区二区久久久| 日韩aaa久久蜜桃av| 日本道不卡免费一区| 国产一级片网站| 黄色精品免费| 亚洲图片欧洲图片av| 国产精品久久久久久搜索| 国产精品国产三级国产有无不卡| 亚洲最新av在线| mm1313亚洲国产精品美女| jizz国产在线| 国产一级在线免费观看| 激情都市一区二区| a黄色片在线观看| av软件在线观看|