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

一文掌握契約測(cè)試

開發(fā) 前端
契約測(cè)試主要解決在存在溝通邊界情況下,測(cè)試替身(Test Double)與生產(chǎn)代碼表現(xiàn)可能不一致的問(wèn)題。在契約測(cè)試中,契約由代碼生成,保持與現(xiàn)實(shí)同步,而且應(yīng)用可以獨(dú)立于其它應(yīng)用而僅基于契約進(jìn)行快速測(cè)試。

領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)因?yàn)槲⒎?wù)的流行而再次火了起來(lái),契約測(cè)試也是一樣。

為了在微服務(wù)開發(fā)模式下跨團(tuán)隊(duì)協(xié)調(diào)更有效率,提升持續(xù)集成流水線自動(dòng)化水平,契約測(cè)試有效彌補(bǔ)了集成測(cè)試的不足,強(qiáng)勢(shì)C位出鏡。

本文將通過(guò)逐步介紹契約測(cè)試是什么,怎么做,有哪些工具,有哪些最佳實(shí)踐和經(jīng)驗(yàn)教訓(xùn),帶您一起徹底掌握契約測(cè)試。

什么是契約測(cè)試

契約測(cè)試(Contract testing)是一種測(cè)試技術(shù),它通過(guò)以隔離檢查集成點(diǎn)上的每個(gè)應(yīng)用的方式,確保應(yīng)用發(fā)送或接收的消息符合調(diào)用雙方共識(shí),并允許隨著時(shí)間的推移進(jìn)行演化。

為什么要做契約測(cè)試

契約測(cè)試主要解決在存在溝通邊界情況下,測(cè)試替身(Test Double)與生產(chǎn)代碼表現(xiàn)可能不一致的問(wèn)題。在契約測(cè)試中,契約由代碼生成,保持與現(xiàn)實(shí)同步,而且應(yīng)用可以獨(dú)立于其它應(yīng)用而僅基于契約進(jìn)行快速測(cè)試。

由于集成測(cè)試容易受到網(wǎng)絡(luò)緩慢或不可靠,以及服務(wù)不可靠等因素的影響而運(yùn)行緩慢或失敗,所以通常會(huì)引入測(cè)試替身來(lái)代替真實(shí)外部服務(wù),以快速完成覆蓋度更廣的測(cè)試,讓測(cè)試真正起到作用。

但是,這樣做的同時(shí),帶來(lái)了測(cè)試替身是否可以持續(xù)準(zhǔn)確表示外部服務(wù)的問(wèn)題。于是,需要單獨(dú)補(bǔ)充運(yùn)行一組契約測(cè)試,來(lái)檢查所有對(duì)測(cè)試替身調(diào)用的返回結(jié)果總是與對(duì)外部服務(wù)調(diào)用的返回結(jié)果相同。

契約測(cè)試的定位

金字塔模型是構(gòu)建健康、快速、可維護(hù)測(cè)試集的成熟理論。

契約測(cè)試適合歸屬于服務(wù)測(cè)試(Service Tests)層,因?yàn)樗鼈儓?zhí)行得很快,也不需要和外部服務(wù)集成來(lái)運(yùn)行。契約測(cè)試運(yùn)行于發(fā)布版本之前,為成功集成提供信心。

契約測(cè)試的價(jià)值

眾所周知,越是在項(xiàng)目生命周期的后期發(fā)現(xiàn)Bug,其修復(fù)的成本就越高。

不同于端到端(E2E)測(cè)試,契約測(cè)試可以在開發(fā)人員推送代碼之前運(yùn)行,在開發(fā)階段提早發(fā)現(xiàn)問(wèn)題。

契約測(cè)試還有很多端到端測(cè)試不具備的好處:

  • 不需要調(diào)用其它組件,運(yùn)行得很快。
  • 編寫測(cè)試不需要了解系統(tǒng)全貌,更容易維護(hù)。
  • 問(wèn)題只存在于被測(cè)試組件中,更容易調(diào)試和修復(fù)。
  • 極易反復(fù)運(yùn)行。
  • 每個(gè)組件獨(dú)立測(cè)試,不會(huì)引發(fā)流水線構(gòu)建時(shí)間大幅增長(zhǎng)。

引入契約測(cè)試,還會(huì)帶來(lái)如下福利:

  • 在提供者API就緒之前就可以開發(fā)消費(fèi)者應(yīng)用。
  • 為提供者供應(yīng)準(zhǔn)確的需求
  • 會(huì)收獲一組文檔化良好的用例,它們確切地顯示了如何使用提供者。
  • 提供者對(duì)API變更更有信息,可以準(zhǔn)確知道使用者感興趣的字段,方便地移除未使用的字段,以及添加新的字段。
  • 對(duì)提供者API進(jìn)行修改,可以立即看到會(huì)影響哪些使用者。

沒(méi)有兩個(gè)團(tuán)隊(duì)是完全一樣的,契約測(cè)試也不是萬(wàn)能的,關(guān)鍵要看契約測(cè)試可以為團(tuán)隊(duì)和項(xiàng)目帶來(lái)什么。

契約測(cè)試適合的場(chǎng)景

契約測(cè)試可以用于任何需要通信的兩個(gè)服務(wù),比如Web前端與后端API服務(wù)。

在微服務(wù)架構(gòu)體系中,因?yàn)榇嬖诟鄨F(tuán)隊(duì)獨(dú)立、服務(wù)間調(diào)用及服務(wù)單獨(dú)演進(jìn)的情形,契約測(cè)試有了更好更大的用武之地。良好的契約測(cè)試,使得開發(fā)人員很容易避免版本地獄,是微服務(wù)開發(fā)和部署的利器。

概念術(shù)語(yǔ)

契約測(cè)試主要涉及如下概念術(shù)語(yǔ):

  • 消費(fèi)者(Consumer):對(duì)于調(diào)用,發(fā)起請(qǐng)求的一方。對(duì)于MQ,為接收消息的一方。
  • 提供者(Provider):對(duì)于調(diào)用,響應(yīng)請(qǐng)求的一方。對(duì)于MQ,為生成消息的一方。
  • 契約(Contract):消費(fèi)者和提供者之間的共識(shí),是一系列交互的集合。對(duì)于HTTP調(diào)用,包括描述消費(fèi)者向提供者發(fā)送什么的預(yù)期請(qǐng)求,以及描述消費(fèi)者希望提供者返回的最小期望響應(yīng)。對(duì)于消息交互,則描述消費(fèi)者希望得到的最小期望消息。

契約測(cè)試模式

契約測(cè)試分為消費(fèi)者驅(qū)動(dòng)(consumer-driven)和提供者驅(qū)動(dòng)(Provider-driven)兩種模式。

消費(fèi)者驅(qū)動(dòng)更具哲學(xué)意義,將API的消費(fèi)者置于設(shè)計(jì)過(guò)程的核心,來(lái)倡導(dǎo)更好的內(nèi)部微服務(wù)設(shè)計(jì)。該模式的優(yōu)點(diǎn)在于,只有消費(fèi)者正在使用的部分會(huì)得到測(cè)試,而提供者可以自由地更改消費(fèi)者不使用的任何其它部分,而不必破壞任何現(xiàn)有測(cè)試。

提供者驅(qū)動(dòng)思路較為常規(guī),更適合開放數(shù)據(jù)或系統(tǒng)的場(chǎng)景。

無(wú)論采用哪種風(fēng)格,關(guān)鍵在于獲得契約測(cè)試的好處,實(shí)現(xiàn)引入契約測(cè)試的目的。

契約測(cè)試基本步驟

1、消費(fèi)者驅(qū)動(dòng)

消費(fèi)者驅(qū)動(dòng)的契約測(cè)試運(yùn)行步驟如下:

  • 消費(fèi)者基于提供者的mock編寫和執(zhí)行消費(fèi)者測(cè)試
  • 消費(fèi)者方通過(guò)消費(fèi)者測(cè)試生成契約,并將契約共享給提供者
  • 提供者根據(jù)契約編寫測(cè)試

2、提供者驅(qū)動(dòng)

提供者驅(qū)動(dòng)模式由提供者定義契約并驅(qū)動(dòng)整個(gè)過(guò)程。

契約測(cè)試工具

流行的契約測(cè)試工具為:

  • Pact:是一個(gè)命令行工具,反饋時(shí)間更短,有助于消費(fèi)者和生產(chǎn)者之間更好地溝通。
  • Spring Cloud Contract:主要用于JVM環(huán)境,也容易擴(kuò)展到非JVM環(huán)境,主要適用于生產(chǎn)者驅(qū)動(dòng)的契約測(cè)試。

利用Pact進(jìn)行消費(fèi)者驅(qū)動(dòng)的測(cè)試

利用Pact進(jìn)行契約測(cè)試的整個(gè)流程示意如下。

1、消費(fèi)者生產(chǎn)代碼

//消費(fèi)者期望從提供者處獲得的User數(shù)據(jù)類
data class User(
val name: String,
val lastName: String,
val age: String,
)

//消費(fèi)者處調(diào)用提供者獲取User對(duì)象的客戶端類
@Service
class UserClient {
fun getUser(): User {
return RestTemplate().exchange(
providerBaseUrl + "/user",
HttpMethod.GET,
HttpEntity(Headers()),
User::class.java

2、為消費(fèi)者編寫測(cè)試

@PactFolder("target/pacts") //存儲(chǔ)pact文件的位置
@ExtendWith(PactConsumerTestExt::class, SpringExtension::class)
class ConsumerContractTest {

//@Pact接受提供者名稱、消費(fèi)者名稱兩個(gè)參數(shù)
@Pact(provider = "user-provider-service", consumer = "user-consume-service")
fun userPact(builder: PactDslWithProvider): RequestResponsePact {
//使用pact DSL創(chuàng)建一個(gè)期望的響應(yīng)體樣本
val responseBody = LambdaDsl.newJsonBody { user ->
user.stringType("name", "someName")
user.stringType("age", "20")
user.stringType("lastName", "someLastName")
}

//使用pact DSL構(gòu)建請(qǐng)求流。當(dāng)提供者接收到GET /user請(qǐng)求時(shí),使用上面定義的樣本進(jìn)行響應(yīng)
return builder
.given("a user is present") //定義提供者狀態(tài)
.uponReceiving("a request to get user")
.pathFromProviderState("/user", "/user")
.method("GET")
.willRespondWith()
.body(responseBody.build())
.toPact()
}

//測(cè)試
//使用者向提供者M(jìn)ockServer發(fā)起請(qǐng)求,并對(duì)響應(yīng)體進(jìn)行斷言
@Test
fun `should return user`(mockServer: MockServer) {
val url = mockServer.getUrl() + "/user"

val user = UserClient().getUser(url)

//斷言key,而不是value,提升健壯性
assertTrue(user.hasProperty("age"))
assertTrue(user.hasProperty("name"))
assertTrue(user.hasProperty("lastName"))
}
}

3、生成契約文件

一旦上面的測(cè)試通過(guò)了,就會(huì)在 target/pacts 文件夾中生成一個(gè)pact契約文件,文件名稱為user-consume-service-user-provider-service.json,文件內(nèi)容如下:

{
"provider": {
"name": "user-provider-service"
},
"consumer": {
"name": "user-consume-service"
},
"interactions": [
{
"description": "a request to get user",
"request": {
"method": "GET",
"path": "/user",
"generators": {
"path": {
"type": "ProviderState",
"expression": "/user",
"dataType": "STRING"
}
}
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json; charset=UTF-8"
},
"body": {
"lastName": "someLastName",
"name": "someName",
"age": "20"
},
"matchingRules": {
"body": {
"$.name": {
"matchers": [
{
"match": "type"
}
],
"combine": "AND"
},
"$.age": {
"matchers": [
{
"match": "type"
}
],
"combine": "AND"
},
"$.lastName": {
"matchers": [
{
"match": "type"
}
],
"combine": "AND"
}
},
"header": {
"Content-Type": {
"matchers": [
{
"match": "regex",
"regex": "application/json(;\\s?charset=[\\w\\-]+)?"
}
],
"combine": "AND"
}
}
}
},
"providerStates": [
{
"name": "a user is present"
}
]
}
],
"metadata": {
"pactSpecification": {
"version": "3.0.0"
},
"pact-jvm": {
"version": "4.1.9"
}
}
}

4、利用Broker共享契約

Pact Broker是一個(gè)用于共享消費(fèi)者驅(qū)動(dòng)的契約,并驗(yàn)證結(jié)果的應(yīng)用程序,對(duì)于Pact創(chuàng)建的契約做了優(yōu)化,但也可以用于任何可以序列化為JSON的契約。

Pact Broker既支持在云上使用,也可以在本地部署。

以下是一個(gè)利用Docker Compose來(lái)本地部署Pack Broker的描述文件。

version: '3'

services:
postgres:
image: postgres
healthcheck:
test: psql postgres --command "select 1" -U postgres
ports:
- "5432"
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
POSTGRES_DB: postgres

broker_app:
image: dius/pact-broker
ports:
- "80:80"
links:
- postgres
environment:
PACT_BROKER_DATABASE_USERNAME: postgres
PACT_BROKER_DATABASE_PASSWORD: password
PACT_BROKER_DATABASE_HOST: postgres
PACT_BROKER_DATABASE_NAME: postgres
PACT_BROKER_LOG_LEVEL: DEBUG

以下是Pact Broker啟動(dòng)后的界面樣子。

接下來(lái)就可以使用pack-jvm的pactPublish命令將契約文件發(fā)布到Broker。

首先在build.gradle文件中添加需要的配置。

pact {
publish {
pactBrokerUrl = "http://localhost:80"
pactDirectory = "target/pacts"
}
}

然后,運(yùn)行如下命令發(fā)布契約。

./gradlew pactPublish

命令執(zhí)行成功后,即可在Pact Broker上看到已發(fā)布的契約。

同時(shí),可以在Broker上查看契約細(xì)節(jié)。

至此,消費(fèi)者方已完成契約創(chuàng)建、發(fā)布等全部工作。

5、提供者端驗(yàn)證

如下為提供者的生產(chǎn)代碼。

@RestController
class UserService {
@GetMapping("/user")
fun getUser(): Map<String, String> {
return mapOf(
"name" to "Foo",
"lastName" to "Bar",
"age" to "22"
)
}
}

以下代碼用于提供者對(duì)契約的驗(yàn)證。

@RunWith(SpringRestPactRunner::class)
@Provider("user-provider-service") //提供者名稱
@PactBroker(
host = "localhost",
port = "80",
scheme = "http",
consumers = ["user-consume-service"],
) //Pact Broker及消費(fèi)者信息
@SpringBootTest(classes = [PactproviderApplication::class], webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT, properties = ["server.port=8080"])
class UserServiceProviderTests {
@TestTarget
val target: HttpTarget = HttpTarget("localhost", 8080)

@MockkBean
lateinit var userService: UserService

@Before
fun setup() {
//如下配置用于讓 pact 在測(cè)試完成后,將測(cè)試結(jié)果發(fā)送到 broker
System.setProperty("pact.verifier.publishResults", "true")
}

@Test
@State("a user is present") //對(duì)應(yīng)于契約中的提供者狀態(tài),以及消費(fèi)者測(cè)試中的 given
fun `should have a customer`() {
//以下用于定義 userService 的 mock 行為
every { userService.getUser() } returns mapOf(
"name" to "someName",
"lastName" to "someLastName",
"age" to "22"
)
}
}

以下為測(cè)試運(yùn)行結(jié)果的樣子。

至此,已完成提供者測(cè)試,并證實(shí)了契約被正確履行。

在Broker上,可以看到契約被驗(yàn)證通過(guò)。

至此,消費(fèi)者、提供者一起完成了整個(gè)契約測(cè)試。

利用SCC進(jìn)行提供者驅(qū)動(dòng)的測(cè)試

利用Spring Cloud Contract進(jìn)行契約測(cè)試的過(guò)程示意如下。

SCC各組件相互關(guān)系描述如下。

1、提供者添加SCC依賴和maven插件

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-contract-verifier</artifactId>
<scope>test</scope>
</dependency>

<plugin>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
<extensions>true</extensions>
</plugin>

2、提供者定義契約

SCC允許通過(guò)groovy、yaml、代碼等多種方式定義契約。

契約中包含在body中定義的消息示例及在matcers中定義的字段匹配器等。

request:
method: PUT
url: /customers
body:
name: John Don
Phone: 1234567890
headers:
Content-Type: application/json
matchers:
body:
- path: $.['name']
type: by_regex
regexType: as_string
- path: $.['phone']
type: by_regex
value: "[0-9]{10}"
response:
status: 200
body:
reference: 1122334455
headers:
Content-Type: application/json
matchers:
body:
- path: $.['reference']
type: by_regex
value: "[0-9]{5}"

3、提供者驗(yàn)證契約

首先創(chuàng)建一個(gè)測(cè)試基類,以便使用命令來(lái)生成測(cè)試代碼。

測(cè)試基類的作用是在每次測(cè)試運(yùn)行之前初始化提供者API和其他配置。

public class BaseTestClass {
@BeforeEach
public void setup(){
RestAssuredMockMvc.standaloneSetup(new CustomerRestController());
}
}

接下來(lái),框架將在maven插件被構(gòu)建過(guò)程調(diào)用后,基于契約生成測(cè)試代碼。

測(cè)試代碼將向提供者發(fā)送帶有契約中示例數(shù)據(jù)的請(qǐng)求,并解析響應(yīng),根據(jù)契約驗(yàn)證響應(yīng)。

@Test
void validate_shouldCreateCustomer() throws Exception {
// given:
MockMvcRequestSpecification request = given()
.header("Content-Type", "application/json")
.body("{\"name\":\"John Don\",\"phone\":1234567890}");

// when:
ResponseOptions response = given().spec(request)
.put("/customers");

// then:
assertThat(response.statusCode()).isEqualTo(200);
assertThat(response.header("Content-Type")).matches("application/json.*");
// and:
DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
assertThatJson(parsedJson).field("['reference']").matches("[0-9]{5}");
}

4、存儲(chǔ)契約

提供者生成的契約jar文件,可以發(fā)布到Nexus、JFrog等構(gòu)建庫(kù)中存儲(chǔ),同時(shí)和其他maven構(gòu)建一樣,可以通過(guò)group Id、artifact id、version等識(shí)別和獲得。

5、消費(fèi)者驗(yàn)證契約

在消費(fèi)者端,SCC框架為其提供了一個(gè)Stub Runner,它可以獲取存根定義并將其注冊(cè)到WireMock服務(wù)器。而該Mock服務(wù)器將模擬測(cè)試用例提供者的API,以支持消費(fèi)者驗(yàn)證契約。

因此,首先需要為消費(fèi)者應(yīng)用添加stub runner的maven依賴。

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-contract-stub-runner</artifactId>
<scope>test</scope>
</dependency>

以下為消費(fèi)者契約測(cè)試代碼。

其中@AutoConfigureStubRunner用于指定契約存根的maven組件信息,包括group id、artifact id和端口號(hào)。然后stub runner就可以從本地或遠(yuǎn)程存儲(chǔ)庫(kù)獲取存根定義。

如下測(cè)試代碼將調(diào)用端口為6565的mock服務(wù)器,并對(duì)響應(yīng)進(jìn)行斷言。

@SpringJUnitConfig(CustomerClient.class)
@AutoConfigureStubRunner(ids = {"space.gavinklfong.demo:customer-service:+:stubs:6565"},
stubsMode = StubRunnerProperties.StubsMode.LOCAL)
public class CustomerClientIntegrationTests {

private CustomerClient customerClient;
@BeforeEach
void setup(){
customerClient = new CustomerClient(“http://localhost:6565);
}

@Test
void testCustomerCreation(){
Customer customer = new Customer(“Peter Pan”, 2233445566);
String ref = customerClient.create(customer);
assertNotNull(ref);
assertEquals(5, ref.length());
assertTrue(isNumeric(ref));
}

}

最佳實(shí)踐

契約測(cè)試有如下最佳實(shí)踐。

  • 契約測(cè)試的關(guān)注點(diǎn)應(yīng)該是請(qǐng)求和響應(yīng)的消息,而不是其行為
  • 契約測(cè)試應(yīng)該與數(shù)據(jù)無(wú)關(guān)
  • 基于Broker將整個(gè)過(guò)程與CI集成
  • pact用于契約測(cè)試,而不是功能測(cè)試
  • 只針對(duì)那些一旦發(fā)生變化就會(huì)影響消費(fèi)者的事情進(jìn)行斷言
  • 將最新的契約提供給提供者

經(jīng)驗(yàn)教訓(xùn)

1、讓所有人都上船

契約測(cè)試需要跨團(tuán)隊(duì)協(xié)作,盡快讓各方都加入進(jìn)來(lái),就模式和工具等各方面達(dá)成一致,否則很快就會(huì)遇到麻煩。

2、不要低估學(xué)習(xí)曲線

契約測(cè)試是一種新型的測(cè)試方法,即使擁有豐富的單元測(cè)試、集成測(cè)試等其它測(cè)試類型的豐富經(jīng)驗(yàn),也并不能代表可以編寫有價(jià)值、可維護(hù)的契約測(cè)試,真正的挑戰(zhàn)在于如何處理API和契約隨時(shí)間的變化。

3、溝通仍然是必要的

工具并不能代替彼此之間的交流,契約測(cè)試也是一樣,至少在初始階段。而在后期,消費(fèi)者更新契約之前,仍然有必要事先與提供者進(jìn)行討論。

4、Pact更好用

Spring Cloud Contract不太適合消費(fèi)者驅(qū)動(dòng)的契約測(cè)試,總是需要消費(fèi)者等待提供者完成相關(guān)工作,而Pact則不需要這種等待。

另外,SCC使用Groovy編寫的契約需要手動(dòng)與消費(fèi)者代碼保持同步,而Pact的API則相當(dāng)成熟,會(huì)自動(dòng)化生成各種代碼和文件。同時(shí)SCC在提供者端提供的的設(shè)置和斷言選項(xiàng)較少。Pact的社區(qū)支持也相對(duì)較好。

Pact對(duì)多語(yǔ)言的支持也更好。

小技巧

可以使用swagger-diff工具比較兩個(gè)版本的API

swagger-diff工具可以用來(lái)比較兩個(gè)Swagger API規(guī)范,并將結(jié)果輸出到HTML或Markdown文件中。

責(zé)任編輯:武曉燕 來(lái)源: 今日頭條
相關(guān)推薦

2023-08-01 09:27:44

Golang模糊測(cè)試

2023-12-21 17:11:21

Containerd管理工具命令行

2022-12-20 07:39:46

2021-05-12 18:22:36

Linux 內(nèi)存管理

2023-10-24 11:44:21

2025-05-21 09:32:28

2020-10-09 07:56:52

Linux

2023-12-15 09:45:21

阻塞接口

2017-11-28 15:20:27

Python語(yǔ)言編程

2020-12-18 11:54:22

Linux系統(tǒng)架構(gòu)

2023-03-10 07:57:26

2021-02-22 09:05:59

Linux字符設(shè)備架構(gòu)

2021-06-04 09:35:05

Linux字符設(shè)備架構(gòu)

2024-11-19 09:00:00

Pythondatetime模塊

2025-04-18 05:50:59

Spring接口Aware

2023-08-24 16:50:45

2018-06-07 13:17:12

契約測(cè)試單元測(cè)試API測(cè)試

2022-08-04 14:38:49

vue3.2setup代碼

2019-03-18 11:15:07

Linux性能網(wǎng)絡(luò)

2022-10-21 18:31:21

ETL
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

精品国产一区二区三区四区vr| 日韩中文字幕在线| 动漫av网站免费观看| 天堂av中文在线资源库| 日韩av中文字幕一区二区| 色偷偷av亚洲男人的天堂| 日本xxxx免费| 一二区成人影院电影网| 亚洲精品福利视频网站| 免费毛片一区二区三区久久久| 中文字幕欧美人妻精品一区蜜臀| 欧美一区高清| 亚洲欧洲一区二区三区久久| 91插插插影院| 亚洲日本天堂| 亚洲精选视频在线| 少妇精品久久久久久久久久| 亚洲美女综合网| 蜜桃视频一区二区三区在线观看| 欧美日本在线视频中文字字幕| 国产肉体xxxx裸体784大胆| 亚洲精品无播放器在线播放| 精品久久中文字幕| 国产精品久久成人免费观看| 黄上黄在线观看| 成人黄色在线视频| 亚洲xxxx18| 中文字幕+乱码+中文乱码www| 亚洲人人精品| 欧美日韩国产成人在线观看| 蜜桃av免费观看| 久久综合影院| 日韩精品极品视频| 欧美性生交xxxxx| 久久九九精品视频| 欧美日韩色一区| 成年人在线观看视频免费| 久久青草伊人| 精品久久久久久久久久久久| www.男人天堂网| а√天堂资源地址在线下载| 国产精品欧美极品| 欧美一区二区福利| 涩爱av在线播放一区二区| 国产成人精品三级麻豆| 91久久夜色精品国产网站| 中文字幕第三页| 丝袜亚洲精品中文字幕一区| 欧洲成人在线视频| 九九热精品视频在线| 亚洲电影在线| 97欧美精品一区二区三区| 青春草免费视频| 欧美另类女人| 欧美激情一区二区三区久久久| 欧美丰满熟妇bbbbbb| 国产精品久久久久9999赢消| 日韩中文字幕在线视频| 国产一区在线观看免费| 99久久精品网站| 久久久精品一区二区| 污污的视频在线免费观看| 91九色精品国产一区二区| 久久精品欧美视频| 粉嫩av性色av蜜臀av网站| 自拍视频亚洲| 午夜精品一区二区三区视频免费看 | 精品一区二区在线免费观看| 国产日产欧美精品| 国产欧美熟妇另类久久久 | 欧美高清视频在线高清观看mv色露露十八 | 国产精品亚洲综合| 特级丰满少妇一级aaaa爱毛片| 99国产精品久久久久久久久久久| 蜜桃网站成人| 最新97超碰在线| 亚洲欧美二区三区| 国产不卡一区二区视频| 欧美电影网址| 在线电影一区二区三区| 蜜臀视频在线观看| 妖精视频一区二区三区| 日韩一区视频在线| 久久免费视频99| 久久久精品性| 91免费看片在线| 人成网站在线观看| 国产日韩av一区二区| 黄色www在线观看| av伦理在线| 欧美私人免费视频| 蜜桃视频无码区在线观看| 亚洲福利天堂| 久久国产精品久久久| 久久久国产高清| 久久99久久精品| 国产伦精品一区二区三区四区视频| 水中色av综合| 亚洲免费观看视频| 免费日韩视频在线观看| 国产一区二区三区免费观看在线 | 在线亚洲人成电影网站色www| 日日干夜夜操s8| 草草视频在线一区二区| 亚洲桃花岛网站| 久久艹精品视频| 日韩电影免费在线| 国模一区二区三区私拍视频| 91caoporn在线| 欧美日韩国产精品一区| 91香蕉视频在线观看视频| 精品一区免费| 久久久久久美女| 一区二区国产欧美| 久久久久88色偷偷免费| 免费看欧美黑人毛片| 日本一区二区三区中文字幕| 日韩精品亚洲元码| 久久精品久久精品久久| 九九视频精品免费| 亚洲成人a**址| 345成人影院| 亚洲国语精品自产拍在线观看| 日韩精品久久久久久久的张开腿让| 香蕉久久a毛片| 国产一区二区三区四区五区在线| 国产在线观看av| 欧洲亚洲精品在线| 天天躁日日躁aaaxxⅹ| 亚洲精品护士| 成人91视频| 欧美人与性动交α欧美精品图片| 欧美群妇大交群的观看方式| 欧美三级视频网站| 天堂久久一区二区三区| 你懂的网址一区二区三区| 爱情岛亚洲播放路线| 日韩欧美国产成人一区二区| 欧美xxxooo| 激情久久久久久久久久久久久久久久| 日韩精品极品视频在线观看免费| 中文不卡1区2区3区| 亚洲精品国产精品乱码不99按摩| 久久婷婷一区二区| 成人午夜激情在线| 久久久国内精品| 一区二区三区亚洲变态调教大结局| 久久精品国产一区| 97在线公开视频| 亚洲三级电影网站| 色偷偷中文字幕| 狠狠爱成人网| 国产精品国色综合久久| 视频一区视频二区国产精品| 中文字幕免费观看视频| 国产精品女同一区二区三区| 视频二区在线播放| 亚洲色图国产| 国产精品国产三级国产专区53 | 欧美18xxxxx| 在线视频一区二区三区| 一级片久久久久| 久久精品国产一区二区三| 在线国产伦理一区| 精品国产一区二区三区性色av| 欧美成人在线影院| 欧美熟妇交换久久久久久分类| 婷婷中文字幕综合| japanese中文字幕| 久久精品国产一区二区| 日本国产中文字幕| 日韩福利视频一区| 国产精品入口尤物| 羞羞视频在线免费国产| 亚洲国产美女精品久久久久∴| 可以免费在线观看的av| 国产视频一区在线观看 | av一级久久| 久久久久久欧美| 国产高清视频在线播放| 51精品国自产在线| 日韩乱码在线观看| 中文字幕免费一区| 五月天丁香社区| 蜜臀99久久精品久久久久久软件 | 久久福利精品| 在线视频不卡一区二区| 第四色在线一区二区| 国产精品狠色婷| av网址在线| 亚洲欧洲在线视频| 国产aⅴ一区二区三区| 欧美视频中文在线看| 91麻豆精品成人一区二区| 9久草视频在线视频精品| 久久久久国产一区| 亚洲国产mv| 一本一道久久a久久精品综合| 哺乳一区二区三区中文视频| 国产精品欧美日韩久久| 超碰中文在线| 精品久久久999| 男女网站在线观看| 日韩免费一区二区三区在线播放| 欧美一区二区三区久久久| 亚洲黄色录像片| 九九热免费在线| 99在线视频精品| 久久久久久久久久毛片| 日韩精品午夜视频| 九九爱精品视频| 五月婷婷亚洲| 色姑娘综合网| 午夜a一级毛片亚洲欧洲| 97影院在线午夜| 欧美成人毛片| 日韩av免费一区| 华人av在线| 欧美激情网站在线观看| 欧美18一19xxx性| 亚洲视频一区二区三区| 香蕉视频黄色片| 精品久久久久久综合日本欧美 | 欧美激情喷水| 高清欧美性猛交| 91网在线看| 久久成人在线视频| 欧美激情视频在线播放| 在线视频日韩精品| 激情视频在线观看免费| 亚洲精品有码在线| 天天干,夜夜爽| 欧美精品一区二| 亚洲国产精品久久久久久久| 欧美福利视频一区| 91九色蝌蚪91por成人| 欧美伊人久久大香线蕉综合69| 精品国产一区二区三区四| 欧美日韩精品中文字幕| 欧美日韩一二三四区| 午夜在线成人av| 99精品视频99| 欧美丝袜一区二区三区| 日韩精品手机在线| 欧美性xxxx18| 波多野结衣一本一道| 日本韩国欧美一区| 乱子伦一区二区三区| 欧美性色综合网| 进去里视频在线观看| 欧美在线免费观看亚洲| 中文字幕免费在线看| 欧美欧美欧美欧美| 国产成人精品一区二区无码呦| 91精品国产综合久久久久久久久久 | 少妇av片在线观看| 国产精品毛片高清在线完整版| 麻豆一区在线观看| 亚洲免费视频成人| 国产亚洲成人av| 精品国产精品三级精品av网址| 黄色片网站在线免费观看| 91国在线观看| 91国产精品一区| 日韩免费性生活视频播放| 欧美黑人视频一区| 国产精品免费播放| 日韩最新免费不卡| 亚洲小说区图片区都市| 久久久最新网址| 毛片免费看不卡网站| 国产精品久久久久久超碰| 4438五月综合| 国产尤物99| 精品国产一级毛片| 欧美另类videos| 在线视频日韩| 最新天堂在线视频| 波多野结衣亚洲一区| 九色porny自拍视频| 亚洲日本中文字幕区| 日本天堂在线视频| 91福利小视频| 国产日本精品视频| 日韩激情片免费| 麻豆视频网站在线观看| 97视频色精品| 日本电影久久久| 精品日韩欧美| 国产精品videosex性欧美| www.99热这里只有精品| 美女任你摸久久| 婷婷五月精品中文字幕| 国产精品免费久久| 国产午夜视频在线播放| 欧美日韩国产免费| 婷婷五月综合久久中文字幕| 在线观看亚洲视频| 国产精品一二三产区| 成人激情综合网| 国产99久久精品一区二区300| 色中文字幕在线观看| 免费在线欧美黄色| 精品无码av一区二区三区不卡| 欧美激情中文字幕一区二区| 国产午夜久久久| 欧美男生操女生| 国产在线视频网址| 7777免费精品视频| 日本精品国产| 亚洲午夜激情| 久久综合网络一区二区| www.啪啪.com| 亚洲乱码日产精品bd| 日韩精品在线一区二区三区| 亚洲第一av在线| av网址在线免费观看| 国产精品九九九| 亚洲调教一区| 欧美视频在线免费播放| 国产精品亚洲一区二区三区在线| 精品日韩在线视频| 色成人在线视频| 日本五码在线| 2019中文字幕在线| theporn国产在线精品| 亚洲国产精品女人| 蜜臀91精品一区二区三区| 欧美另类z0zx974| 日韩欧美一区二区三区| 桃花色综合影院| 国模私拍一区二区三区| 日韩欧美中文字幕一区二区三区| 亚洲欧洲精品一区二区三区波多野1战4 | 四虎视频在线精品免费网址| 欧美重口乱码一区二区| 亚洲一区国产一区| 国产一级伦理片| 精品福利免费观看| 特级丰满少妇一级aaaa爱毛片| 色综合久久久久久中文网| 榴莲视频成人app| 异国色恋浪漫潭| 国产精品888| 久久久久噜噜噜亚洲熟女综合| 日韩一卡二卡三卡四卡| 永久免费网站在线| 亚洲自拍偷拍区| 欧美黄免费看| 在线观看成人动漫| 粉嫩老牛aⅴ一区二区三区| 青青国产在线| 国产精品极品尤物在线观看| 成人国产精品一级毛片视频| www午夜视频| 亚洲精品第一国产综合野| 国产91免费看| 欧美中文字幕在线| av亚洲免费| 91aaa精品| 亚洲国产欧美一区二区三区丁香婷| 欧美77777| 国产成人精品综合久久久| 成人无号精品一区二区三区| 91视频这里只有精品| 亚洲综合久久久| 青青草超碰在线| 国产精品va在线| 欧美阿v一级看视频| 亚洲一区二区在线免费| 欧美性猛交xxxx久久久| 自拍视频在线| 国产精品视频免费一区二区三区| 国产麻豆综合| 熟女av一区二区| 亚洲国产欧美一区二区三区同亚洲| 韩国主播福利视频一区二区三区| 亚洲一区二区精品在线| 成人精品电影在线观看| 亚洲精品一区二三区| 久久五月天综合| 欧美调教网站| 国产精品自拍视频在线| 亚洲国产精品久久久久秋霞影院 | 国产 日韩 欧美 精品| 欧美一区二区三区四区在线| 三上亚洲一区二区| 亚洲精品乱码久久久久久蜜桃欧美| 日韩欧美aaa| av免费在线免费| 奇米精品在线| 国产成人一区二区精品非洲| 亚洲天堂视频网站| 俺去了亚洲欧美日韩| 欧美日韩一本| 免费黄频在线观看| 色综合久久中文字幕综合网| 18网站在线观看| 日韩在线观看电影完整版高清免费| 国产成人精品亚洲777人妖 |