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

React全家桶與前端單元測試藝術

開發 開發工具
具體到單元測試方面,得益于Virtual DOM本身和模塊化設計(不然全家桶白叫了),React全家桶明顯更優秀些。我們本篇中的測試有三個目標:學得快,寫得快,跑得快。

TL;DR——什么是好的單元測試?

其實我是個標題黨,單元測試根本沒有“藝術”可言。

好的測試來自于好的代碼,如果說有藝術,那也是代碼的藝術。

注:以下“測試”一詞,如非特指均為單元測試。

[[203448]]

單元測試的好壞在于“單元”而不在“測試”。如果一個系統毫無單元可言,那就沒法進行單元測試,幾乎只能用Selenium做大量的E2E測試,其成本和穩定性可想而知。科學的單元劃分可以讓你擺脫mock,減少依賴,提高并行度,不依賴實現/易重構,提高測試對業務的覆蓋率,以及易學易用,大幅減少測試代碼。

最好的單元是返回簡單數據結構的函數:函數是最基本的抽象,可大可小,不需要mock,只依靠傳參。簡單數據結構可以判等。 最好的測試工具是Assert.Equal這種的:只是判等。判等容易,判斷發生了什么很難。你可以看到后面對于DOM和異步操作這些和副作用相關的例子都靠判等測試。把作用冪等于數據,拿到數據就一定發生作用,然后再測數據,是一個基本思路。

以上是你以前學習測試第一天就會的內容,所以不存在門檻。

為什么不談TDD?

首先,TDD肯定是有價值的(價值大小不論)。反對TDD的原因一般比較明顯,對于TDD是否帶來正收益不確定(動機不足)。 某些項目質量要求很高,預算寬綽,TDD勢在必行。某些項目比較緊急,或者并非關鍵或無長期維護計劃,TDD理由就不充分。

為什么談測試?

因為測試難。

第一難學,第二難寫。寫測試是個挺困難的活,要在測試里正確重演業務要費好大勁,只能靠反復練習。雖然這些測試在某些項目中是值得的,但是可能并不適合其他某些項目的基本情況。

測試難,就代表訓練成本高,生產成本也高,收益就下降。要提高采用TDD的動機,與其說服別人,不如從簡化測試開始。

[[203449]]

(圖片來自:http://t.cn/Rpw9WKg)

為什么談前端測試?

一般項目都是后端測試覆蓋率高,同時后端套路也比較固定。測RESTful API粒度足夠大,可以很好地避開實現并且覆蓋業務。同時RESTful API一般也正好對應Web框架的Action handler,在這里同時它粒度也足夠小,剛好可以直接調用而不啟動真的Web server,使得測試最大程度并行化。所以這樣測試收益總是最高的,爭議很小。

前端不說套路不固定,測不測都有待商榷。因為前端流派不統一,資源不規則,邊界也不清晰,有渲染又有點業務,有導航有請求,很多團隊不測試/測Model/測Component/測E2E,五花八門。 但得益于JavaScript本身,前端測試其實是可以非常高效的。

下面你可以看到各種極簡極快的測試工具和測試方式,并且它們完全可以貫穿開發始終,而非僅給Hello World體量項目準備的,你可以在很大的全家桶項目中完全機械地套用這些方法。(機械也是極限的一部分,你不應該在使用工具過程中面臨太多抉擇,而應當專注于將業務翻譯成測試)。

為什么談React全家桶?

前端從每周刷新一個框架,穩定到了Angular, React, Vue3個主流框架并存的階段。網絡中爭論這三個框架蓋的樓已經可以繞太陽系了。根據蓋的各種大樓看來,現在哪個更優秀還沒個定論。不過具體到單元測試方面,得益于Virtual DOM本身和模塊化設計(不然全家桶白叫了),React全家桶明顯更優秀些。

測試工具

我們本篇中的測試有三個目標:學得快,寫得快,跑得快。

[[203450]]

(圖片來自:http://t.cn/RpwCke3)

平臺上Selenium, Phantom, Chrome, 包括Karma都比較重,最好的測試框架就是直接跑在node上的。本著極限編程的原則,我們將測試本身和測試環境盡可能簡化,以達到加快測試速度,最終反饋到開發速度的目的。

我們使用AVA進行測試,它非常簡潔,速度非常快,和mocha不同,它默認會啟動多線程并發測試。因此我們的測試必須減少共享狀態來提高并發能力,不然就會出現意想不到的錯誤。安裝和運行:

  1. yarn add ava 
  2. ava --watch 

這樣可以運行并watch測試。改變代碼測試結果會立刻改變,你也可以看到友善的錯誤信息,以及expected和actual之間的diff。寫下第一段測試:

  1. import test from 'ava' 
  2.  
  3. test(t => { 
  4.   t.is(1 + 1, 2) 
  5. }) 

除了is方法以外,我們還會用到deepEqual和true方法。好,你現在已經完全會用AVA了。其他的功能我們完全不關心。

Redux測試 (Model測試)

Redux就是用一堆Reducer函數來reduce所有事件用來做全局Store的狀態機(FSM)。用源碼本身介紹它甚至比用上一小段文字介紹還快:

  1. const createStore = reducer => { 
  2.   let state, listeners = [] 
  3.  
  4.   const dispatch = action => { 
  5.     state = reducer(state, action) 
  6.     listeners.forEach(listeners => listeners()) 
  7.   } 
  8.  
  9.   return { 
  10.     getState() { return state }, 
  11.     subscribe(listener) { 
  12.       listeners.push(listener) 
  13.       return () => { listenerslisteners = listeners.filter(l => l !== listener)} 
  14.     }, 
  15.     dispatch, 
  16.   } 

這是一個簡化版的代碼,去掉了拋錯等等細節,但功能是完整的。把你自己寫的reducer扔進去,然后可以發事件來使其更新,你還可以訂閱它來拿狀態。有點像Event Sourcing,以消息而非調用來處理邏輯,更新和訂閱的邏輯不在一起(事件是寫模型,各種view就是多個讀模型)。

reducer幾乎包括了我們所有前端業務的核心,測好它就測了大半。它們全都是(State, Action) => nextState形式的純函數,無異步操作,用swtich case來模擬模式匹配來處理事件。比如用喜聞樂見的簡陋版的棧停車場舉例:

  1. export const parkingLot = (state = [], action) => { 
  2.   switch (action.type) { 
  3.     case 'parkingLot/PARK': 
  4.       return [action.car, ...state] 
  5.     case 'parkingLot/PICK': 
  6.       const [_, ...rest] = state 
  7.       return rest 
  8.     default: return state 
  9.   } 

Reducer是這么用的:

  1. const store = createStore(parkingLot) 
  2. store.subscribe(() => renderMyView(store.getState())) 
  3. store.dispatch({ type: 'parkingLot/PARK' }) 

好,現在你又理解了Redux。那我們可以看看怎么測試上面的parkingLot reducer了:

  1. test('parking lot', t => { 
  2.   const initial = parkingLot(undefined, {}) 
  3.   t.deepEqual(initial, [], 'should be empty when init') 
  4.  
  5.   const parked = parkingLot(initial, { type: 'parkingLot/PARK', car: 'Tesla Model S' }) 
  6.   t.deepEqual(parked, ['Tesla Model S'], 'should park Model S in lot') 
  7.  
  8.   const picked = parkingLot(parked, { type: 'parkingLot/PICK' }) 
  9.   t.deepEqual(picked, [], 'should remove the car') 
  10. }) 

它就是你第一天學測試就會寫的那種測試。這些測試不受任何上下文影響,是冪等的。試著把那幾個const聲明的state挪到任何地方,你都可以發現測試還是正確的,這和我們平常小心翼翼分離各個測試case,并用beforeEach和afterEach重置截然不同。

[[203451]]

(圖片來自:http://t.cn/RpwS3AK)

測試Reducer是非常機械的,你不需要問自己“我到底應該測哪些東西”,只需要機械地測試初始state和每個switch case就好了。(小秘密:redux-devtools寫完實現,在瀏覽器里打開,反過來還可以自動生成各種框架的測試代碼,粘貼回來就行了。推薦不寫測試的項目嘗試下,反正白送的測試……而且跟你寫的沒兩樣)

隨著業務變得復雜,當state樹變大時,我們可以將reducer結構繼續往下抽,并繼續傳遞事件,函數沒有this,重構起來比普通OO要簡單得多,就不贅述了。這時候測試還是完全一樣的,這種樹形結構保證了我們能最大限度地覆蓋一個bounded context—也就是root reducer。

另外更好的方式是用t.is(斷言引用相同)而非t.deepEqual。但是JavaScript對象本身是可變的,引入immutable.js可以讓你只用t.is測試,不過immutable的API有點別扭,不展開了。

組件測試 (View測試)

React是一個View library,它干的活就是DOM domain里的兩個事:渲染和捕獲事件。我們在這里依然從簡,只用stateless component這個子集,雖然在用到生命周期方法的時候需要用一下class,但絕大多數時候應該只用stateless component。

它以Virtual DOM的形式封裝了惡心的瀏覽器基礎設施,讓我們以函數和數據結構來描述組件,所以和大部分框架不同,我們的測試依然可以在node上并行運行。如果用Karma + Chrome真正地渲染測試,你會發現共享一個瀏覽器實例的測試非常慢,幾乎無法watch測試,因此我們的TDD cycle就會變得不那么流暢了。

最基本的就是state => UI這種純函數組件:

  1. const Greeter = ({ name }) => <p>Greetings {name}!</p> 

 

使用的時候就像HTML一樣傳遞attribute就可以了。

  1. render(<Greeter name="React"/>, document.body) 

最簡單的測試還是判等,我們用一個叫jsx-test-helpers的庫來幫我們渲染:

  1. import { renderJSX, JSX } from 'jsx-test-helpers' 
  2.  
  3. const Paragraph = ({ children }) => <p>{children}</p> 
  4. const Greeter = ({ name }) => <Paragraph>Greetings {name}!</Paragraph> 
  5.  
  6. test('Greeter', t => { 
  7.   t.is(renderJSX(<Greeter name="React"/>),  
  8.        JSX(<Paragraph>Greetings React!</Paragraph>),  
  9.        'should render greeting text with name') 
  10. }) 

這里我多加了一層叫做Paragraph的組件,它的作用僅僅是傳遞給p標簽,children這個prop表示XML標簽傳進來的子元素。多加這層Paragraph是為了展示renderJSX只向下渲染了一層,而非最終需要渲染的p標簽。這樣我們在View上的測試粒度就會變得更小,成本更低,速度更快。

[[203452]]

(圖片來自:http://t.cn/RpwYskG)

View不像業務本身那么穩定,細粒度低成本的快速測試更劃算些,這也是為什么我們的View都只是接受參數渲染,這樣你只用測很少的case就能保證View可以正確渲染。假如你的FSM Model有M種可能性,View顯示的邏輯有N種,如果將兩個集成在一起測試可能就需要M×N種Path,如果分開測就有M+N種。View和Model的邊界清晰時,你的Model測試不容易被更困難的View測試干擾,View測試也減少了混沌程度,需要測試的情形就減少了。

我們的組件不應該只有渲染,還有事件,比如我們封裝個TextField組件:

  1. const TextField = ({ label, onChange }) => <label> 
  2.   {label} 
  3.   <input type="text" onChange={onChange} /> 
  4. </label> 

 

當然我們還可以判等,只要onChange函數引用相同就好了。

  1. test('TextField', t => { 
  2.   const onChange = () => {} 
  3.   const actual = renderJSX(<TextField label="Email" onChange={onChange} />
  4.   const expected = JSX(<label> 
  5.     Email 
  6.     <input type="text" onChange={onChange}/> 
  7.   </label>
  8.   t.is(actual, expected) 
  9. }) 

當然有時候你的組件更復雜些,測試時并不關心組件是不是完全按你想要的樣子渲染,可能你想像jQuery一樣選擇什么,觸發什么。這樣可以用更主流的enzyme來測試:

  1. import {shallow} from 'enzyme' 
  2. import sinon from 'sinon' 
  3.  
  4. test('TextField with enzyme', t => { 
  5.   const onChange = sinon.spy() 
  6.   const wrapper = shallow(<TextField label="Email" onChange={onChange} />
  7.   t.true(wrapper.contains(<label>Email</label>), 'should render label') 
  8.  
  9.   const event = { target: { value: 'foo@bar.com' } } 
  10.   wrapper.find('input').simulate('change', event) 
  11.   t.true(onChange.calledWith(event)) 
  12. }) 

這里用的shallow顧名思義,也是向下渲染一層。此外我們還用了spy,這樣測試就變得有點復雜了,丟掉了我們之前聲明式的優雅,所以組件還是小一點、一下測完比較好。

還不夠快?Facebook就覺得不夠快,他們覺得View測試成本比較浪費,干脆搞了個Snapshot測試——意思就是照個像,只斷言它不變。下次誰改了別的地方不小心影響到這里,就會掛掉,如果無意的就修好,如果有意的話和git一樣commit一下就修好了:

  1. import render from 'react-test-renderer' 
  2.  
  3. test('Greeter', t => { 
  4.   const tree = render.create(<Greeter name="React"/>).toJSON() 
  5.   t.snapshot(tree, 'should not change') 
  6. }) 

當你修改Greeter的時候,測試就會掛掉,這時候運行:

  1. ava --update-snapshots 

就好了。Facebook自家的Jest對snapshot的支持更好,當snapshot不匹配時按個y/n就完事了,夠快了吧。要有更快的可能就是不測了……

小結

這節里我們展示了3種測試View的不同方式,它們都比傳統框架更簡單更快速。我們的思路還是以判等為主,但不同于Model,粒度越大越好。View測試粒度越小越好,足夠小、足夠冪等之后,其實不用測試你也可以發現組件總是按照預期工作。相比之下MVVM天然有一種讓View和Model粒度擬合的傾向,很容易讓測試變得既難測又缺乏價值。

[[203453]]

異步Effect測試

這算個續集……異步操作不復雜的項目可以無視這段,可以選擇性不測。

React先解決了惡心的DOM問題,把Model的問題留下了。然后Redux把同步邏輯解決了,其實前端還留下異步操作的大問題沒有解決。這種類似“Unix只做一件事”的哲學是React全家桶的根基。我們用一個叫做Redux-saga的庫來展現全家桶的異步測試怎么寫,Redux模仿的目標是Elm architecture,但是簡化掉了Elm的作用模型,只保留了同步模型,Redux-saga其實就是把Elm的作用模型又拿回來了。

Saga是一種worker模式,很早之前在Java社區就存在了。Redux-saga抽象出來多種通用的作用比如call / takeEvery等等,然后有了這些作用,我們又可以愉快地判等了。比如:

  1. import { takeEvery, put, call, fork, cancel } from 'redux-saga/effects' 
  2.  
  3. function *account() { 
  4.   yield call(takeEvery, 'login/REQUESTED', login) 
  5. function *login({ name, password }) { 
  6.   try { 
  7.     const { token } = yield call(fetch, '/login', { method: 'POST', body: { name, password } }) 
  8.     yield put({ type: 'login/SUCCEEDED', token }) 
  9.   } 
  10.   catch (error) { 
  11.     yield put ({ type: 'login/FAILED', error }) 
  12.   } 

這段代碼乍看起來很丑,這是因為它把程序里所有異步操作全都集中在自己身上了。其他部分都可以開心地發同步事件了,此外有了Saga之后Redux終于有了“用事件觸發事件”的機制了,只用redux,應用復雜到一定程度你一定會想這個問題的。

這是個最普通的API處理saga,一個account worker看到每個’login/REQUESTED’就會forward給login worker(takeEvery),讓它繼續管下面的事。然后login worker拿到消息就會去發請求(call),之后傻傻地等著回復,或者是出錯。最后它會發出和結果相關的事件。用這個方式你可以輕松解決瘋狂難度的異步問題。

  1. test('account saga', t => { 
  2.   const gen = account() 
  3.   t.deepEqual(gen.next().value, call(takeEvery, 'login/REQUESTED', login)) 
  4. }) 
  5.  
  6. test('login saga', t => { 
  7.   const gen = login({ name: 'John', password: 'super-secret-123'}) 
  8.  
  9.   const request = gen.next().value 
  10.   t.deepEqual(request, call(fetch, '/login', { method: 'POST', body: { name: 'John', password: 'super-secret-123'} })) 
  11.   const response = gen.next({ token: 'non-human-readable-token' }).value 
  12.   t.deepEqual(response, put({ type: 'login/SUCCEEDED', token: 'non-human-readable-token' })) 
  13.   const failure = gen.throw('You code just exploded!').value 
  14.   t.deepEqual(failure, put({ type: 'login/FAILED', error: 'You code just exploded!'})) 
  15. }) 

你看我們的測試連異步操作都還可以無恥地判等。call就是以某些參數調用某個函數,put就是發事件。

可以試著把fetch覆蓋成空函數,你可以發現實際上副作用根本沒發生,“fetch到底是個啥”對測試一點影響都沒有。你可能發現了,其實saga就是用數據結構表示作用,而不著急執行,在這里又走回冪等的老路了。這和React Virtual DOM的思路異曲同工。

結語

首先是文章開頭提到的TL;DR的內容。函數是個好東西,測函數不等同“測1+1=2”這種沒營養的單元,函數是可以包含很大上下文的。這種輸入輸出的模型既簡單又有效。

我們消滅了mock,減少了依賴,并發了測試,加快了速度,降低了門檻,減少了測試路徑等等。如果你的React項目原來在TDD的邊緣搖擺不定,現在是時候入一發這種唯快不破了。

全家桶讓Model/View/Async這三者之間的邊界變得清晰,任由業務變更,它們之間的職責是不會互相替代的,這樣你測它們的時候才更容易。后端之所以測試穩定是因為有API。所以想讓前端好測也是一樣的思路。

文中好多次提到“冪等”這個概念,冪等可以讓你減少測試的case,寫代碼更有底氣。拋開測試不談,代碼冪等的地方越多,程序越可控可預期。其實仔細思考一下我們的實際項目,大部分業務都是非常確定的,并沒有什么隨機因素。為什么最后還是會出現很多隨機現象呢?

聲明優于命令,描述發生什么、想要什么比親自指導具體步驟好。

消息機制優于調用機制。Smalltalk > Simula。其實RESTful API一定程度上也是消息。簡單的對象直接互相作用是完全沒問題的,人作為復雜對象主要通過語言媒介來交流,聽到內容思考其中的含義,而不是靠肢體接觸,或者像連體嬰兒那樣共享器官。所以才有一句俗語叫“你的對象都想成長為Actor”。

從View的幾種測試里我們也可以看到,測試并不是只有測或者不測這兩種選擇,我們老提測試金字塔,意思是測試可多可少,不同層級的測試保持正金字塔形狀比較健康,像今天我們說的就可以大幅加寬你測試金字塔的底座。所以你的項目有可能測試過少,也可能測試過度,所以時間可以動態調整。

沒用全家桶的項目可以把“大Model小View”的思想拿走,這樣更容易于專注價值。盡量抽出Model層,不要把邏輯寫在VM里,看那樣似省事,行數在測試里都還回來了。

【本文是51CTO專欄作者“ThoughtWorks”的原創稿件,微信公眾號:思特沃克,轉載請聯系原作者】

戳這里,看該作者更多好文

責任編輯:趙寧寧 來源: 51CTO專欄
相關推薦

2017-09-10 17:41:39

React全家桶單元測試前端測試

2017-01-14 23:42:49

單元測試框架軟件測試

2016-09-21 15:35:45

Javascript單元測試

2021-10-12 19:16:26

Jest單元測試

2022-03-15 11:55:24

前端單元測試

2009-09-01 10:20:06

protected方法單元測試

2016-09-14 21:55:33

前端測試Karma

2022-10-26 08:00:49

單元測試React

2017-02-21 10:30:17

Android單元測試研究與實踐

2017-04-07 13:45:02

PHP單元測試數據庫測試

2016-09-26 16:42:19

JavaScript前端單元測試

2017-01-16 12:12:29

單元測試JUnit

2017-01-14 23:26:17

單元測試JUnit測試

2017-03-30 07:56:30

測試前端代碼

2020-08-18 08:10:02

單元測試Java

2020-03-19 14:50:31

Reac單元測試前端

2017-03-23 16:02:10

Mock技術單元測試

2021-05-05 11:38:40

TestNGPowerMock單元測試

2023-07-26 08:58:45

Golang單元測試

2020-05-07 17:30:49

開發iOS技術
點贊
收藏

51CTO技術棧公眾號

在线观看国产免费视频 | 蜜臀精品一区二区| 日韩av女优在线观看| 成人全视频在线观看在线播放高清| 郴州新闻综合频道在线直播| 午夜久久久影院| 欧美疯狂性受xxxxx另类| 亚欧在线免费观看| 香蕉视频国产在线| 尤物在线精品| 欧美大片日本大片免费观看| 自拍亚洲欧美老师丝袜| 久久久999久久久| 嫩草影视亚洲| 欧美性20hd另类| 精品一区2区三区| 国产无遮挡裸体免费视频| 清纯唯美激情亚洲| 亚洲精品视频在线| 3d精品h动漫啪啪一区二区| chinese全程对白| 91国产精品| 亚洲免费观看高清完整版在线观看 | 欧美日韩一区二区三| 黄色小视频在线免费看| 日韩中字在线| 欧美高清视频一二三区 | 亚洲天堂av网站| 性直播体位视频在线观看| 91偷拍一区二区三区精品| 91黄视频在线| 亚洲欧洲日韩精品| 国产免费黄色录像| 欧美精品一线| 亚洲国产三级网| 男女超爽视频免费播放| 天堂网www中文在线| 香蕉成人久久| 在线播放国产一区二区三区| av免费一区二区| 免费看a在线观看| 国产一区二区不卡| 国内免费久久久久久久久久久 | 欧美xxxx做受欧美.88| 四虎国产精品永久免费观看视频| 羞羞的视频在线观看| 国产精品久久久久影院老司| 91性高湖久久久久久久久_久久99| 顶级黑人搡bbw搡bbbb搡| 中文字幕精品影院| 欧美日本一区二区三区四区| 欧美黄色免费网址| 欧美日本韩国一区二区| 日韩精品一二区| 少妇高潮 亚洲精品| 91在线第一页| 原纱央莉成人av片| 国产日韩欧美一区二区三区乱码| 国产精品99久久久久久久久久久久| 登山的目的在线| 日本女优一区| xxxxx成人.com| 性欧美18—19sex性高清| 视频精品国内| 亚洲第一精品自拍| 日韩欧美国产片| 51精品视频| 亚洲素人一区二区| 欧美在线视频二区| 午夜精品久久久久久久第一页按摩 | 免费观看精品视频| 日韩大片在线永久免费观看网站| 成人免费av资源| 日韩成人在线视频| 欧美一级高清免费| 欧美黄色高清视频| 丁香五月缴情综合网| 色婷婷综合久色| 看一级黄色录像| 免费一级毛片在线观看| 久久久久久电影| 亚洲999一在线观看www| 五月天激情四射| 午夜欧美精品久久久久久久| 亚洲午夜未满十八勿入免费观看全集| 亚洲欧美天堂在线| 综合另类专区| 欧美三级乱人伦电影| 男人和女人啪啪网站| 亚洲按摩av| 偷窥国产亚洲免费视频| 99热这里只有精品7| 日本aa在线| 亚洲美女精品一区| 欧美高清videos高潮hd| 欧美日韩视频免费| www.av黄色| 2020国产精品久久精品美国| 成人av免费看| 国产永久免费视频| 日韩电影在线观看电影| 91手机视频在线观看| 欧美一级一区二区三区| 国产盗摄一区二区三区| 成人国产精品一区| 夜夜躁狠狠躁日日躁av| 人妖欧美一区二区| 国产精品劲爆视频| 亚洲熟女综合色一区二区三区| 蜜臀av国产精品久久久久| 国产91在线播放精品91| 91精品国产高清一区二区三密臀| 精油按摩中文字幕久久| 国产中文字幕91| 亚洲无码精品国产| 成人av网站免费观看| 国产亚洲精品自在久久| 污视频在线免费观看| 国产精品污网站| 亚洲春色在线视频| 高清精品在线| 欧美色播在线播放| 最好看的中文字幕| 日韩理论在线| 日韩av片永久免费网站| 韩国中文字幕hd久久精品| 成人免费毛片app| 中国人体摄影一区二区三区| 欧美大电影免费观看| 在线影视一区二区三区| 亚洲第一狼人区| 综合久久av| 国产一区二区三区视频在线观看| 在线观看免费国产视频| 久久亚洲风情| 成人高h视频在线| 怡红院av一区二区三区| 国内精品久久影院| 91丨九色丨丰满| 久久精品夜色噜噜亚洲a∨ | 欧美激情aⅴ一区二区三区| 国产成人欧美在线观看| 青青草视频在线观看| 337p粉嫩大胆色噜噜噜噜亚洲| 欧美日韩一区二区三区免费| 成年女人在线看片| 精品捆绑美女sm三区| 黄色网址在线视频| 狠狠综合久久| 国产精品v片在线观看不卡| 午夜黄色小视频| 欧美午夜精品久久久久久浪潮| 999精品免费视频| 日韩精品诱惑一区?区三区| 国产成人免费av电影| 国产精品影院在线| 一个色在线综合| 九九热免费精品视频| 精品一区在线| 国产精品视频在线播放| 亚洲国产精品久久久久久6q| 26uuu久久综合| 成人一级片网站| 狠狠做六月爱婷婷综合aⅴ | 老牛影视免费一区二区| a中文在线播放| 一区二区三区丝袜| 国产精九九网站漫画| av在线不卡免费观看| 欧美国产精品人人做人人爱| 国产综合视频在线| 欧美日韩中文字幕日韩欧美| 国产精品美女高潮无套| 精品福利av| 欧美成人一区二区在线| 成人免费一区| 欧美激情精品久久久久久| 日韩av资源| 51精品国自产在线| 妺妺窝人体色WWW精品| 黑丝一区二区三区| 久久精品人人做人人爽电影| 在线网址91| 欧美精品久久99| 久久亚洲av午夜福利精品一区| 捆绑调教一区二区三区| 欧美国产综合视频| 欧美韩国日本| 中文字幕精品一区二区精品| 亚洲自拍一区在线观看| 国产精品日日摸夜夜摸av| 国模大尺度视频| 久久精品免费| 久久综合一区二区三区| 国产精品亲子伦av一区二区三区| 美女福利视频一区| 在线观看xxx| 88在线观看91蜜桃国自产| 日韩男人的天堂| 综合久久国产九一剧情麻豆| 最新天堂在线视频| 亚洲精品欧美| 狠狠干一区二区| 欧美日韩视频免费看| 668精品在线视频| 五月婷婷深深爱| 欧美精品一级二级三级| 久久精品视频7| 一区二区三区四区不卡在线| 少妇的滋味中文字幕bd| 蜜桃av噜噜一区二区三区小说| av一区二区三区免费观看| 精品国产一区探花在线观看| 国产精品theporn88| 国产精品蜜臀| 日韩的一区二区| 国产欧美日韩成人| 欧美视频一区在线观看| 俄罗斯毛片基地| 99久久久精品免费观看国产蜜| 青青草视频在线免费播放| 五月天久久久| 成人精品水蜜桃| 欧美一级在线| 欧美巨猛xxxx猛交黑人97人| www日本在线| 欧美日韩久久一区二区| 国产一级淫片a视频免费观看| 亚洲国产视频一区| 国产探花在线观看视频| 另类图片国产| 人妻熟妇乱又伦精品视频| 欧美全黄视频| 国产精品啪啪啪视频| 6080成人| 4444欧美成人kkkk| 肉体视频在线| 欧美大奶子在线| 中文字幕伦理免费在线视频| 日韩视频免费在线观看| 137大胆人体在线观看| 日韩欧美一级片| 国产精品一区二区黑人巨大| 亚洲在线中文字幕| www欧美com| 91老师片黄在线观看| 国产真实乱人偷精品| www.爱久久.com| 中文字幕在线播放视频| 91丝袜呻吟高潮美腿白嫩在线观看| av2014天堂网| 久久久精品天堂| 国产毛片欧美毛片久久久| 欧美韩国一区二区| 亚洲精品久久一区二区三区777| 国产乱码精品一区二区三| 欧美日韩第二页| 丝袜美腿亚洲一区二区图片| 亚洲视频在线a| 国产精品九九| www.射射射| 国产精品久久久乱弄| 青春草在线视频免费观看| 亚洲另类春色校园小说| 日本亚洲自拍| 天天综合精品| 91黄色在线看| 玖玖视频精品| 无尽裸体动漫2d在线观看| 国产自产v一区二区三区c| 成年人看片网站| 精品一区二区国语对白| 少妇性饥渴无码a区免费| 久久动漫亚洲| 一区二区三区四区毛片| 丁香婷婷综合五月| 欧美成人午夜精品免费| 东方欧美亚洲色图在线| 亚洲av无码一区二区三区观看| 久久久久久久综合日本| 小泽玛利亚一区| 亚洲动漫第一页| 91在线视频免费播放| 亚洲精品欧美激情| 日韩在线视频免费播放| 一区二区三区在线视频免费| 91精品国产乱码在线观看| 色94色欧美sute亚洲线路一ni| 一级片在线免费观看视频| 欧美精品一区二区三区一线天视频 | 成人在线观看亚洲| 在线观看亚洲视频| 欧洲一区二区三区| 国产精品高潮呻吟久久av野狼| 欧美h版在线观看| 成人激情视频免费在线| 巨人精品**| 国产色综合一区二区三区| 欧美精品一区二区三区中文字幕 | 亚洲激情成人| 亚欧激情乱码久久久久久久久| 岛国av在线一区| 欧美性猛交xxxx乱大交少妇| 国产丝袜美腿一区二区三区| 欧美成人精品激情在线视频| 亚洲蜜臀av乱码久久精品蜜桃| 国产精品一区二区三区四| 欧美性xxxx在线播放| 国产色综合视频| 国产一区二区三区在线看| 电影k8一区二区三区久久| 国产精品一区二区久久久| 日韩精品亚洲aⅴ在线影院| 久久精品人成| 伊人激情综合| 亚洲制服中文字幕| 国产日韩欧美制服另类| 久久艹免费视频| 日韩精品一区二区三区视频在线观看 | 国产精品最新| 国产91沈先生在线播放| 麻豆精品视频在线观看免费| 国产黄色三级网站| 亚洲精品国产精品乱码不99| 最近中文在线观看| 亚洲精品自产拍| av免费观看网址| 日韩一区二区三| 韩国中文字幕hd久久精品| 精品国偷自产在线视频99| 国产精品扒开做爽爽爽的视频| 欧美诱惑福利视频| 精品无人区一区二区| 青青草视频在线视频| 国产又粗又猛又爽又黄91精品| jizz18女人高潮| 在线观看三级视频欧美| 久草在线免费福利资源| 综合网中文字幕| 婷婷六月国产精品久久不卡| 久久久www免费人成黑人精品| 在线国产日韩| 亚洲一区和二区| 亚洲福利视频导航| 人妻无码中文字幕| 久久久久亚洲精品| 国产精品zjzjzj在线观看| 日本久久久网站| 成人性生交大片免费看视频在线| 欧美成人手机视频| 国产日韩一区二区在线观看| 日韩福利视频导航| 国产在线观看h| 91成人免费网站| 国产小视频免费在线网址| 国产精品草莓在线免费观看| 国产欧美日韩一区二区三区四区 | 久久综合激情| 亚洲理论片在线观看| 欧美性videosxxxxx| 一区二区高清不卡| 91在线高清免费观看| 欧美ab在线视频| 精品1卡二卡三卡四卡老狼| 精品电影在线观看| 国产三级视频在线看| 国产精品一区二区三区成人| 偷偷www综合久久久久久久| 国产又粗又猛又爽又黄| 午夜精品久久久久久久| 激情综合闲人网| 91九色视频导航| 一本色道久久综合亚洲精品不| 9久久9毛片又大又硬又粗| 2024国产精品| 在线免费观看一级片| 久久精品免费播放| 精品深夜福利视频| 一本色道久久亚洲综合精品蜜桃| 亚洲视频一区二区在线| 熟妇人妻系列aⅴ无码专区友真希| 少妇高潮久久77777| 香蕉成人app| 日韩av片在线看| 成人综合婷婷国产精品久久免费| 亚洲天堂日韩av| 中文字幕亚洲一区二区三区| 警花av一区二区三区| 97国产精东麻豆人妻电影| 国产日韩欧美综合一区| 99国产精品无码| 欧美变态口味重另类| 在线手机中文字幕| 国产美女精彩久久| 欧美日本三区| 国产精品20p| 亚洲精品91美女久久久久久久| 成人影院在线免费观看| 国产精品久久久久9999爆乳| 国产欧美日韩另类一区|