日本免费精品_最新日韩一区_亚洲视频一区在线_a在线视频观看_天天射夜夜骑_粉嫩av一区二区三区_欧美中日韩免费视频_综合图区欧美_国内精品美女在线观看_午夜精品久久久久久久男人的天堂

首頁 > 學院 > 開發設計 > 正文

文章標題

2019-11-10 20:02:52
字體:
來源:轉載
供稿:網友

先介紹下這篇博文的由來,之前已經對JUnit的使用經行了深入的介紹和演示(參考JUnit學習(一),JUnit學習(二)),其中的部分功能是通過分析JUnit源代碼找到的。得益于這個過程有幸完整的拜讀了JUnit的源碼十分贊嘆作者代碼的精美,一直計劃著把源碼的分析也寫出來。突發奇想決定從設計模式入手賞析JUnit的流程和模式的應用,希望由此能寫出一篇耐讀好看的文章。于是又花了些時日重讀《設計模式》以期能夠順暢的把兩者結合在一起,由于個人水平有限難免出現錯誤、疏漏,還請各位高手多多指出、討論。

測試用例的一生——運行流程圖

這里寫圖片描述

圖一 TestCase運行時序圖

首先,介紹下JUnit的測試用例運行會經過哪些過程,這里說起來有些抽象會讓人比較迷惑,在看了后面章節的內容之后就比較清晰了:

Client(JUnitCore、Eclipse):這里是TestCase開始的地方,如果是Main函數來啟動測試用例的話一般會調用JUnitCore的方法,如果是在Eclipse中使用JUnit插件則實際上調用的是org.eclipse.jdt.internal.junit4.runner.JUnit4TestClassReference這個類。 Request(org.junit.runner.Request):Client會根據測試類或方法而創建一個Request實體,Request包含了要被執行的測試類、測試方法等信息。 RunnerBuilder:在創建后Client調用Request.getRunner()方法獲取用于執行測試的Runner,該過程是由RunnerBuilder這個工廠類完成的。 RunNotifier:在執行Runner.run方法時Client還會傳遞一個RunNotifier對象,是事件的監聽器的管理員。Runner在開始執行、成功、失敗和執行結束時會調用RunNotifier中相應的方法從而發送事件給注冊了的監聽器,JUnit運行的最終結果就是這些監聽器收集展現的。 Runner:從名字可以猜出這里應該是測試用例運行的地方了,在Client調用了Runner.run()方法之后,Runner會先構造Statement對象將所有要執行的邏輯委托給它,接著執行Statement.evaluate()方法。在這期間Runner會觸發RunNotifier(如測試開始、測試結束等等)。 Statement:測試用例的運行時描述,關注于測試用例如何運行和調用測試代碼。比如在執行測試用例前是否有@Before注釋的方法需要調用等信息都會被Runner構造為Statement。

JUnit的類設計和模式應用

這里寫圖片描述

圖二 JUnit的類結構

首先先介紹下JUnit中的模型類(Model),在JUnit模型類可以劃分為三個范圍:

描述模型:是對要執行的測試用例的描述(比如要執行哪個類的哪個方法,是否有指定Runner,使用了哪些注解等),這一層類似于流程文件之于流程引擎——不是用來執行的,而是描述要有哪些環節、細節。個人認為這一模型包括測試類本身(即你自己編寫的測試用例)和Request。其中測試類本身等同于描述文件,Request則記錄了是要運行的Suit、測試類或者是某個具體的方法、過濾器、排序的Comparator等信息(JUnit是支持對測試方法排序和過濾的)。運行時模型:是JUnit中可執行的模型,包括FrameworkMember(org.junit.runners.model.FrameworkMember)及其子類、TestClass(org.junit.runners.model.TestClass)、Statement。FrameworkMember的子類包括FrameworkMethod和FrameworkField分別描述了測試類的方法和變量信息,比如是否為靜態、作用域、包含哪些注解等JUnit運行時需要用到的信息;TestClass的作用有些類似FrameworkMember,是針對測試的Class的描述。Statement在上面已經介紹過是對測試執行流程和細節的描述。

結果模型:JUnit中用于描述用例的類,包括Description(org.junit.runner.Description)、Result(org.junit.runner.Result)、Failure(org.junit.runner.notification.Failure)。Description是對測試用例的描述(測試名稱、所在Class的名字、是否是suit等等)只為RunNotifier提供服務。Result是運行結果的描述,用例執行完成后RunNotifier的 fireTestRunFinished(final Result result)方法會被觸發,傳入的Result實例描述了運行耗時、忽略的用例次數、是否成功等信息。Failure則是用例失敗后Runner傳遞給RunNotifier的對象用于描述錯誤信息,特別包含了錯誤的StackTrace。 言歸正傳,下面討論設計模式和JUnit的源碼:

工廠方法模式、職責鏈:用例啟動,Client在創建Request后會調用RunnerBuilder(工廠方法的抽象類)來創建Runner,默認的實現是AllDefaultPosibilitiesBuilder,根據不同的測試類定義(@RunWith的信息)返回Runner。AllDefaultPosibilitiesBuilder使用職責鏈模式來創建Runner,部分代碼如下。代碼A是AllDefaultPosibilitiesBuilder的主要構造邏輯構造了一個【IgnoreBuilder->AnnotatedBuilder->SuitMethodBuilder->JUnit3Builder->JUnit4Builder】的職責鏈,構造Runner的過程中有且只有一個handler會響應請求。代碼B是Junit4Builder類實現會返回一個BlockJUnit4ClassRunner對象,這個是JUnit4的默認Runner。public Runner runnerForClass(Class<?> testClass) throws Throwable { List<RunnerBuilder> builders = Arrays.asList( ignoredBuilder(), annotatedBuilder(), suiteMethodBuilder(), junit3Builder(), junit4Builder()); for (RunnerBuilder each : builders) { Runner runner = each.safeRunnerForClass(testClass); if (runner != null) { return runner; } } return null; }

代碼A 職責鏈實現

public class JUnit4Builder extends RunnerBuilder { @Override public Runner runnerForClass(Class<?> testClass) throws Throwable { return new BlockJUnit4ClassRunner(testClass); }}

代碼B JUnit4Builder實現

組合模式:將具備樹形結構的數據抽象出公共的接口,在遍歷的過程中應用同樣的處理方式。這個模式在Runner中的應用不是很明顯,扣進來略有牽強。Runner是分層次的,父層包括@BeforeClass、@AfterClass、@ClassRule注解修飾的方法或變量,它們在測試執行前或執行后執行一次。兒子層是@Before、@After、@Rule修飾的方法或變量它們在每個測試方法執行前后執行。當編寫的用例使用Suit來運行時則是三層結構,上面的父子結構中間插入了一層childrenRunners,也就是一個Suilt中每個測試類都會生成一個Runner,調用順序變成了Runner.run()>childRunner.run()<即遍歷childrenRunners>->testMethod()。ParentRunner中將變化的部分封裝為runChild()方法交給子類實現,達到了遍歷過程使用同樣處理方式的目的——ParentRunner.this.runChild(each,notifier)。public void run(final RunNotifier notifier) { EachTestNotifier testNotifier = new EachTestNotifier(notifier, getDescription()); try { Statement statement = classBlock(notifier); statement.evaluate(); } catch (AssumptionViolatedException e) { testNotifier.fireTestIgnored(); } catch (StoppedByUserException e) { throw e; } catch (Throwable e) { testNotifier.addFailure(e); } } PRivate void runChildren(final RunNotifier notifier) { for (final T each : getFilteredChildren()) { fScheduler.schedule(new Runnable() { public void run() { ParentRunner.this.runChild(each, notifier); } }); } fScheduler.finished(); }

代碼C ParentRunner的組合模式應用

模板方法模式:模板方法的目的是抽取公共部分封裝變化,在父類中會包含公共流程的代碼,將變化的部分封裝為抽象方法由子類實現(就像模板一樣框架式定好的,你去填寫你需要的內容就行了)。JUnit的默認Runner——BlockJUnit4ClassRunner繼承自ParentRunner,ParentRunner類定義了Statement的構造和執行流程,而如何執行兒子層的runChild方法時交給子類實現的,在BlockJUnit4ClassRunner中就是去構造和運行TestMethod,而另一個子類Suit中則是執行子層次的runner.run。

這里寫圖片描述 圖三 RunNotifier的公共方法

private abstract class SafeNotifier { private final List<RunListener> fCurrentListeners; SafeNotifier() { this(fListeners); } SafeNotifier(List<RunListener> currentListeners) { fCurrentListeners = currentListeners; } void run() { synchronized (fListeners) { List<RunListener> safeListeners = new ArrayList<RunListener>(); List<Failure> failures = new ArrayList<Failure>(); for (Iterator<RunListener> all = fCurrentListeners.iterator(); all .hasNext(); ) { try { RunListener listener = all.next(); notifyListener(listener); safeListeners.add(listener); } catch (Exception e) { failures.add(new Failure(Description.TEST_MECHANISM, e)); } } fireTestFailures(safeListeners, failures); } } abstract protected void notifyListener(RunListener each) throws Exception; }public void fireTestRunStarted(final Description description) { new SafeNotifier() { @Override protected void notifyListener(RunListener each) throws Exception { each.testRunStarted(description); } ; }.run(); }

代碼D RunNotifier代碼截取

裝飾模式:保持對象原有的接口不改變而透明的增加對象的行為,看起來像是在原有對象外面包裝了一層(或多層)行為——雖然對象還是原來的類型但是行為逐漸豐富起來。 之前一直在強調Statement描述了測試類的執行細節,到底是如何描述的呢?代碼E展示了Statement的構筑過程,首先是調用childrenInvoker方法構建了Statement的基本行為——執行所有的子測試runChildren(notifier)(非Suit情況下就是TestMethod了,如果是Suit的話則是childrenRunners)。接著是裝飾模式的應用,代碼F是withBeforeClasses()的實現——很簡單,檢查是否使用了@BeforeClasses注解修飾如果存在構造RunBefores對象——RunBefore繼承自Statement。代碼H中的evaluate()方法可以發現新生成的Statement在執行runChildren(fNext.evaluate())之前遍歷所有使用@BeforeClasses注解修飾的方法并執行。產生的效果即使用@BeforeClasses修飾的方法會在所有用例運行前執行且只執行一次。后面的withAfterClasses、withClassRules方法原理一樣都使用了裝飾模式,不再贅述。protected Statement classBlock(final RunNotifier notifier) { Statement statement = childrenInvoker(notifier); statement = withBeforeClasses(statement); statement = withAfterClasses(statement); statement = withClassRules(statement); return statement; } protected Statement childrenInvoker(final RunNotifier notifier) { return new Statement() { @Override public void evaluate() { runChildren(notifier); } }; }

代碼E Statement的構造

protected Statement withBeforeClasses(Statement statement) { List<FrameworkMethod> befores = fTestClass .getAnnotatedMethods(BeforeClass.class); return befores.isEmpty() ? statement : new RunBefores(statement, befores, null); }

代碼F withBeforeClasses實現

public class RunBefores extends Statement { private final Statement fNext; private final Object fTarget; private final List<FrameworkMethod> fBefores; public RunBefores(Statement next, List<FrameworkMethod> befores, Object target) { fNext = next; fBefores = befores; fTarget = target; } @Override public void evaluate() throws Throwable { for (FrameworkMethod before : fBefores) { before.invokeExplosively(fTarget); } fNext.evaluate(); }}

代碼H RunBefores實現

策略模式:針對相同的行為在不同場景下算法不同的情況,抽象出接口類,在子類中實現不同的算法并提供算法執行必須Context信息。JUnit中提供了Timeout、ExpectedException、ExternalResource等一系列的TestRule用于豐富測試用例的行為,這些TestRule的都是通過修飾Statement實現的。修飾Statement的代碼在withRules()方法中實現,使用了策略模式。代碼I描述了JUnit是如何處理@Rule標簽的,withRules方法獲取到測試類中所有的@Rule修飾的變量,分別調用withMethodRules和withTestRules方法,前者是為了兼容JUnit3版本的Rule這里忽略,后者withTestRules的邏輯很簡單首先查看是否使用了@Rule,如存在就交給RunRules類處理。代碼J是RunRules的實現,在構造函數中處理了修飾Statement的邏輯(applyAll方法)——抽象接口是TestRule,根據不同的場景(即使用@Rule修飾的不同的TestRule的實現)選擇不同的策略(TestRule的具體實現),而Context信息就是入參(result:Statement, description:Description)。private Statement withRules(FrameworkMethod method, Object target, Statement statement) { List<TestRule> testRules = getTestRules(target); Statement result = statement; result = withMethodRules(method, testRules, target, result); result = withTestRules(method, testRules, result); return result; }private Statement withTestRules(FrameworkMethod method, List<TestRule> testRules, Statement statement) { return testRules.isEmpty() ? statement : new RunRules(statement, testRules, describeChild(method)); }

代碼I rule的執行

public class RunRules extends Statement { private final Statement statement; public RunRules(Statement base, Iterable<TestRule> rules, Description description) { statement = applyAll(base, rules, description); } @Override public void evaluate() throws Throwable { statement.evaluate(); } private static Statement applyAll(Statement result, Iterable<TestRule> rules, Description description) { for (TestRule each : rules) { result = each.apply(result, description); } return result; }}

代碼J RunRules實現

這里簡單舉一個Timeout的代碼。Timeout首先實現了TestRule方法并在apply中定義了自己的算法——構造一個FailOnTimeout對象并返回。不再詳細描述FailOnTimeout的實現,主要原理就是起一個線程來跑測試代碼并等待線程指定的時間,如果超時就會拋出異常。public class Timeout implements TestRule { private final int fMillis; /** * @param millis the millisecond timeout */ public Timeout(int millis) { fMillis = millis; } public Statement apply(Statement base, Description description) { return new FailOnTimeout(base, fMillis); }}

代碼K Timeout實現

外觀模式:封裝統一的對外接口,隱藏內部各個小模塊之間的調用細節,使得用戶既可以簡單的使用facade來達到目的,必要時又可以自行操作內部對象。這里的舉例可能不是非常明顯。圖四是TestClass的公共方法,代碼L給出了 TestClass(org.junit.runners.model.TestClass)的一小部分代碼,TestClass主要作用是封裝對Class的操作提供了JUnit運行時需要用到的功能并隱藏其中操作的細節。在TestClass內部將功能委托給了三個對象Class(java.lang.Class)、FrameworkMethod、FrameworkField來實現,本身充當了外觀(facade)對外提供了getName、getOnlyConstructor、getAnnotations等等接口,在必要的時又可以通過這個外觀獲取到Class、FrameworkMethod等對象。

這里寫圖片描述

圖四 TestClass的公共方法

public class TestClass { private final Class<?> fClass; private Map<Class<?>, List<FrameworkMethod>> fMethodsForAnnotations = new HashMap<Class<?>, List<FrameworkMethod>>(); private Map<Class<?>, List<FrameworkField>> fFieldsForAnnotations = new HashMap<Class<?>, List<FrameworkField>>(); /** * Creates a {@code TestClass} wrapping {@code klass}. Each time this * constructor executes, the class is scanned for annotations, which can be * an expensive process (we hope in future JDK's it will not be.) Therefore, * try to share instances of {@code TestClass} where possible. */ public TestClass(Class<?> klass) { fClass = klass; if (klass != null && klass.getConstructors().length > 1) { throw new IllegalArgumentException( "Test class can only have one constructor"); } for (Class<?> eachClass : getSuperClasses(fClass)) { for (Method eachMethod : MethodSorter.getDeclaredMethods(eachClass)) { addToAnnotationLists(new FrameworkMethod(eachMethod), fMethodsForAnnotations); } for (Field eachField : eachClass.getDeclaredFields()) { addToAnnotationLists(new FrameworkField(eachField), fFieldsForAnnotations); } } } ……}

代碼L TestClass截取

寫在最后

讀JUnit代碼時確實非常贊嘆其合理的封裝和靈活的設計,自己雖然也寫了幾年代碼但是在JUnit的源碼中收獲很多。由于對源碼的鉆研深度以及設計模式的領會不夠深入,文中有很多牽強和錯誤的地方歡迎大家討論指正。最喜歡的是JUnit對裝飾模式和職責鏈的應用,在看到AllDefaultPossiblitiesBuilder中對職責鏈的應用還覺得設計比較合理,等到看到Statement的創建和組裝就感慨設計的精湛了,無論是基本的調用測試方法的邏輯還是@Before、@After等以及實現自TestRule的邏輯一并融入到Statement的構造中,又不會牽扯出太多的耦合。總之無論是設計模式還是設計思想,歸根結底就是抽取公共部分,封裝變化,做到靈活、解耦。最后說明這篇文章根據的源代碼是JUnit4.11的,maven坐標如下,在JUnit的其它版本中源碼差別比較大沒有研究過。<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> </dependency>

轉自:junit源碼與設計模式欣賞


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
日韩高清不卡在线| www日韩在线观看| 欧美 日韩 中文字幕| 国产丝袜在线播放| 91精品国产手机| 精品视频123区在线观看| av中文网站| 日韩欧美中文视频| 91精品国产高清| 欧美日韩国产区| 欧美亚洲国产日韩| 日韩欧美综合在线| 日韩影院二区| 中文字幕在线精品| 亚洲欧美999| 日本不卡免费高清视频| 国产高清不卡av| 中文字幕 亚洲一区| 国产欧美日韩在线播放| 国产成人精品999| 亚洲 欧美 精品| 国产在线视频不卡| 在线观看免费国产成人软件| 欧美日韩国产大片| 国产三级视频网站| 久久婷婷国产| 国产资源在线观看| 亚洲高清免费一级二级三级| 欧美日韩中文字幕视频| 国产色在线视频| 中文精品在线观看| 日本亚洲欧美天堂免费| 尤物av一区二区| 欧美日韩国产成人| 午夜伊人狠狠久久| 色欧美日韩亚洲| 一区二区日韩av| 国产高清不卡av| 亚洲免费视频一区| 国产一区在线不卡| 一区二区高清在线| 亚洲乱码在线观看| 亚洲综合在线电影| 欧美日韩午夜在线| 日韩三级免费观看| 免费视频国产一区| 中文在线视频| 欧美日韩国产一区中文午夜| 午夜av一区二区| 亚洲福利在线看| 欧美日韩国产不卡| 久草视频在线看| 欧美日韩视频免费| 久久香蕉av| 日韩欧美国产视频| 国产在线欧美| 在线黄色国产电影| 中文字幕欧美亚洲| 亚洲视频在线观看日本a| 在线不卡一区二区| 91精品在线视频观看| 亚洲 欧美综合在线网络| 久久婷婷国产| 精品国产99| 视频一区二区精品的福利| 精品一二三区| av一卡二卡| 一本一道久久a久久精品综合蜜臀| 日韩欧美看国产| 99视频精品全国免费| 亚洲成av人片| 亚洲成av人片在线| 亚洲欧美视频一区二区三区| 欧美一级欧美三级在线观看| 一区二区精品免费| 欧美91精品| 日韩三级免费观看| 亚洲人线精品午夜| 欧美在线视频二区| 最近免费中文字幕在线第一页| 91亚洲欧美| 日韩一级中文字幕| 91精品免费观看| 欧美日韩视频免费播放| 成人久久在线| 欧美日韩久久久| 亚洲开心激情| 精品中文字幕视频| 区日韩二区欧美三区| 亚洲国产午夜精品| 国产欧美日韩精品在线| 中文字幕在线观看视频www| 日韩欧美在线第一页| 影音先锋一区二区资源站| 日韩精品在线免费观看视频| 91精品久久久久久久久久| 国产欧美久久久久久久久| 亚洲成av人综合在线观看| 色国产在线视频| 亚洲美女视频一区| 丰满少妇一区| 亚洲午夜91| 欧美色欧美亚洲高清在线视频| 最新日韩中文字幕| 国产裸舞福利在线视频合集| 日韩av不卡在线观看| 国产福利久久| 麻豆精品99| 亚洲 国产 欧美 日韩| 中文字幕在线亚洲| 国产偷国产偷亚洲清高网站 | 国产网站av| 国产传媒久久久| 欧美另类久久久品| 精品一二三四| 免费在线国产| 影音先锋一区二区资源站 | 中文欧美字幕免费| 丰满少妇一区| 日韩av一区二区在线| 日韩不卡一二三区| 中文字幕欧美国内| 一区二区在线观| 一区二区三区精品在线观看| 一区二区三区中文字幕在线观看| 亚洲v中文字幕| 国产日韩在线亚洲字幕中文| 二区三区中文字幕| 亚洲午夜久久| 欧美日韩国产一中文字不卡| 欧美日韩高清一区二区| 日韩精品 欧美| 国产黄色小视频| 日韩国产在线不卡视频| 国产高清在线一区| 影音先锋一区二区资源站 | aaa免费看大片| 中文字幕日韩欧美| 视频一区三区| 黄色片免费在线| 日韩中文字幕91| 日韩欧美99| 亚洲男人在线| 免费在线视频一级不卡| 国产日韩三级| 91精品国产全国免费观看| 国产一级片在线| 欧美日韩国产高清一区| 最近中文字幕第一页| 国产一区三区三区| 国产在线一在线二| 高清一区二区| 久久精品日韩无码| 中文字幕欧美国内| 77777_亚洲午夜久久多人 | 一区二区日韩视频| 中文字幕在线播放一区| 成人ww免费完整版在线观看| 91精品国产综合久久久久久漫画 | 亚洲一区精品电影| 成年人黄国产| 国产日韩中文字幕在线| 日韩视频 中文字幕| 国产高清精品在线| 亚洲免费观看视频| 91精品婷婷国产综合久久竹菊 | 国产成人精品三级| 成人无遮挡免费网站视频在线观看| 午夜影院在线观看欧美| 国产偷国产偷亚洲清高网站| 免费视频一区三区| 最近中文av字幕在线中文 | 亚洲精品中文字幕乱码三区不卡| 日韩不卡一区二区| 亚洲第一视频网站| 尤物在线精品| 国产xxx在线| 日韩视频在线免费看| 天堂在线一区二区三区| 欧美日韩国产中文| 91精品国产综合久久久久久漫画| 亚洲成av人片| 亚洲a中文字幕| 欧美日韩国产综合视频在线观看中文 | 国产黄色一级片| 国产字幕在线看| av免费网站在线| 日韩欧美在线影院| 一区在线播放视频| 精品人妻二区中文字幕| 粉嫩喷白浆久久| 精品国产乱码久久久久久牛牛| 久久精品在线观看| 中文网丁香综合网| 黄色资源在线观看| 日韩欧美一卡二卡| 91精品国产91久久| 香蕉视频亚洲一级| 91精品久久久久久久91蜜桃| 国产日韩精品在线观看| 在线视频一区二区三区在线播放 | 国产小视频在线| 国产在线www| 久久精品在线免费观看| 日本国产在线视频| 亚洲黄色在线观看| 国产激情在线观看| 欧美日韩免费精品| 日韩视频不卡中文| 日韩字幕在线观看| 日韩精品在线观看视频| 国产欧美日韩中文字幕| 视频一区二区不卡| 国产一级粉嫩xxxx| 亚洲一区不卡在线| 亚洲一区视频在线观看视频| 国产激情在线| 日韩三级视频在线播放| 国产v日产∨综合v精品视频| 国产www.大片在线| 国产欧美第一页| 精品激情国产视频| 日韩亚洲欧美中文在线| 欧美国产一区视频在线观看| 在线日韩欧美| 日韩在线中文| 日韩精品第一区| 欧美亚洲国产激情| 不卡福利视频| 日韩国产在线观看一区| 香蕉视频亚洲一级| 日韩精品在线第一页| 日韩精品视频在线观看网址| 99视频一区| 欧美不卡一区二区| 日韩欧美一二三四区| 日韩av一区在线| 91精品国产丝袜白色高跟鞋| 亚洲二区自拍| 国产黄色在线网站| av午夜在线| 精品欧美久久久| 久久99久久久久| 日韩中文字幕在线视频播放| 日韩 欧美 亚洲| 国产一区久久| 一区精品在线播放| 日韩精品在线免费看| 中文字幕在线视频久| 欧美日韩一级视频| 91精品在线观看视频| a级在线免费观看| 中文字幕乱码在线| 91精品观看| 99精品视频国产| 亚洲成年网站在线观看| 欧美在线视频第一页| 1区2区3区在线视频| 日韩三级免费观看| 国产欧美中文字幕| 日韩精品在线观看视频| 国产性一级片| 欧美三级在线播放| 亚洲成av人片一区二区密柚| 一区二区三区四区五区视频在线观看| 91麻豆免费视频网站| 国产劲爆久久| 在线观看精品国产| 中文字幕最新精品| 在线精品观看| 国内精品露脸在线视频播放| 欧美日韩精品是欧美日韩精品| 中文字幕亚洲乱码| 欧美日韩综合色| 亚洲经典中文字幕| 亚洲福利视频在线| 国产黄色精品| 日韩欧美国产综合| 日韩你懂的电影在线观看| 日韩激情一区| 日韩高清不卡一区二区| 免费视频国产一区| 一区二区日韩免费看| 亚洲热在线观看| 国产中文在线| 韩国v欧美v日本v亚洲| 日韩中文在线视频| 欧美日韩国产免费| 欧美日韩国产一二三| 欧美日韩中文字幕日韩欧美| 日韩av一区二区在线| 中文字幕精品国产| 国产欧美中文在线| 一区视频在线播放| 欧美日韩中文字幕综合视频| 91精品国产色综合久久不卡蜜臀| 黄色一区二区在线| 国产在线拍偷自揄拍精品| 欧美日韩第一区日日骚| 日韩精品视频在线观看视频| 精品乱子伦一区二区| 午夜福利一区二区三区| av一卡二卡| 国产区视频在线观看| 91欧美日韩在线| 欧美久久久久久蜜桃| 午夜国产在线视频| 麻豆一区二区99久久久久| 国产一区不卡精品| 日韩中文字幕观看| 日韩精品高清不卡| 日韩在线三区| 免费国产h视频在线观看86| 日韩欧美中文字幕在线视频| 国产福利免费观看| 国产欧美综合在线观看第十页| 亚洲最新免费视频| 久草视频观看| 中文字幕日韩免费视频| 欧美婷婷精品激情| 九九视频精品免费| 最近高清中文在线字幕在线观看1| 国产色综合网| 欧美日韩综合在线观看| 日韩欧美在线中文字幕| 精品综合久久久久| 精品播放一区二区| 日韩欧美三级视频| 91精品国产综合久久久久久 | 中文字幕精品在线| 自拍日韩亚洲一区在线| 蜜桃久久av| 色国产在线视频| 亚洲大片精品永久免费| 日韩欧美在线影院| 日韩av在线中文字幕| 99久久精品国产亚洲| 欧美日韩国产中文精品字幕自在自线| 国产一级片网站| av免费观看国产| 一本一道久久a久久精品综合蜜臀| 欧美高清一区| 精品亚洲成a人片在线观看| 日韩一二三四区| 日韩一级二级三级| 亚洲成av人片| 91精品综合久久| 亚洲综合在线小说| 99视频在线看| 日韩不卡在线播放| 国产无套粉嫩白浆在线2022年| 日韩中文字幕网| 欧美在线视频一区二区| 91九色精品视频| 日本不卡一区在线| 九七久久人人| 亚洲午夜久久| 亚洲免费中文字幕| 欧美日韩在线综合| 欧美日韩激情一区| 99精品免费观看| 国产黄色小视频| 国产丝袜一区二区| 日韩视频在线观看视频| 久久久精品欧美| 二区视频在线观看| 欧美 中文字幕| 日韩视频国产视频| 日韩精品福利视频| 欧美日韩在线中文字幕| 日韩精品一页| 91精品国产自产91精品| 国产在线二区| 精品日韩av| 久久91精品久久久久久秒播| 91久久精品在线| 正在播放日韩精品| 欧美成人精品在线| 欧美 亚洲 精品 三区| 91精品国产91久久久久久久久| 中文字幕在线导航| 国产亚洲视频中文字幕视频| 国产欧美日韩精品在线观看| 亚洲综合日韩| 99精品免费观看| 天天综合日日夜夜精品| 91午夜在线| 精品熟女一区二区三区| 国产日韩综合| av中文网站| 久久久精品福利| 亚洲a一级视频| 亚洲va韩国va欧美va精品| 久久婷婷亚洲| 欧美日韩在线视频免费观看| 欧美一级搡bbbb搡bbbb| 欧美日韩色综合| 日韩网站中文字幕| 国产中文在线| 蜜桃视频一日韩欧美专区|