青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

S.l.e!ep.¢%

像打了激速一樣,以四倍的速度運轉,開心的工作
簡單、開放、平等的公司文化;尊重個性、自由與個人價值;
posts - 1098, comments - 335, trackbacks - 0, articles - 1
  C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

用CPPUnit做單元測試
例子程序下載:http://www.codeproject.com/library/Using_CPPUnit/my_tests.zip
CPPUnit最新版本免費下載:
http://cppunit.sourceforge.net/
CPPUnit是基于C++的單元測試框架,可以有效提高開發的系統質量。
引言:
QA過程常采用兩種測試方法:
1、單元測試(acceptance測試):為軟件系統中的每一個邏輯單元制定的一系列驗證方法。僅測試單元的功能,而不考慮各個單元之間的協作關系。
2、系統測試(集成測試):測試系統的功能,尤其是各單元模塊之間的協作關系。
下面要講的是如何采用CPPUnit對C/C++工程進行單元測試。
文章假設讀者熟悉單元測試的概念及其重要性。
單元測試設計:
想一下開發團隊中常常出現的一種場景:程序員正在使用Debugger工具測試代碼。采用Debugger工具可以可以隨時隨地檢查每個變量。步步跟蹤,檢查變量的值是否異常。Debugger是一種強有力的調試工具,但是調試速度相當慢,并且包含不少錯誤。在這種情況下調試是讓人崩潰的。這些復雜有大量重復的驗證方法是可以通過自動化的手段完成的,需要做的是選擇合適的工具并編寫少量代碼。
下面要介紹的工具叫做“單元測試框架”,借助這種工具,可以通過編寫一些小的模塊來完成模塊(可以是類、函數和庫)的單元測試。
下面來看一個例子:編寫一個小的模塊,主要功能是求兩數之和。其C語言代碼如下:
BOOL addition(int a, int b)
{
??? return (a + b);
}
測試單元編寫成另外一個模塊(C函數)。該模塊測試所有可能的求兩數之和的組合,通過返回True或False來判斷被測模塊是否通過了測試。代碼如下:
BOOL additionTest()
{
??? if ( addition(1, 2) != 3)
??? {
??????? return (FALSE);
??? }

??? if ( addition(0, 0) != 0)
??? {
??????? return (FALSE);
??? }

??? if ( addition(10, 0) != 10)
??? {
??????? return (FALSE);
??? }

??? if ( addition(-8, 0) != -8)
??? {
??????? return (FALSE);
??? }

??? if ( addition(5, -5) != 0)
??? {
??????? return (FALSE);
??? }

??? if ( addition(-5, 2) != -3)
??? {
??????? return (FALSE);
??? }

??? if ( addition(-4, -1) != -5)
??? {
??????? return (FALSE);
??? }

??? return (TRUE);
}
測試的情況包括:
正數+正數
0+0
正數+0
負數+0
正數+負數
負數+正數
負數+負數
每一次測試都是通過對比被測模塊的返回值和期望值,如果二者不同,返回FALSE。如果最終返回TRUE,說明模塊通過了所有的測試。
這個用以測試其他模塊的小模塊(函數)被稱為Test Case, 其中包含了程序員需要對被測單元的一系列檢查。每一個確認(對被測單元的一次調用)都必須和被測單元相對應。在這個例子中,檢查了“求和操作”在操作數符號不同的情況下的運行情況。當然了,還需要另外寫一些Test Case來驗證其他情況下的運行情況。比如其他一些常見的加法組合。例子如下:
int additionPropertiesTest()
{
??? //conmutative: a + b = b + a
??? if ( addition(1, 2) != addition(2, 1) )
??? {
?return (FALSE);
??? }

??? //asociative: a + (b + c) = (a + b) + c
??? if ( addition(1, addition(2, 3)) != addition(addition(2, 1), 3 ) )
??? {
?return (FALSE);
??? }

??? //neutral element: a + NEUTRAL = a
??? if ( addition(10, 0) != 10 )
??? {
?return (FALSE);
??? }

??? //inverse element: a + INVERSE = NEUTRAL
??? if ( addition(10, -10) != 0 )
??? {
?return (FALSE);
??? }

??? return (TRUE);
}
上面的例子測試了多個數據相加順序不同的情況。
上述的兩個Test Case組成了一個Test Suite,Test Suite是指用來測試同一被測單元的一組Test Case。
在開發被測模塊時必須同時編寫這些Test Case和Test Suite的代碼,被測模塊變更時,要同時變更(有時需要增加)相應的Test Case和Test Suite。
舉例來說,當求和模塊升級為可以對小數求和的模塊,就必須變更Test Case和Test Suite,加入諸如addDecimalNumbersTest之類的Test Case。
極限編程建議程序員在編寫目標模塊之前就開發出所有單元測試中要用到的Test Case。其主要理由是:一旦程序員處于開發過程之中,那么他就進入了一個持續改進的階段,必須同時考慮單元模塊功能、需要公布的接口、需要給方法傳遞的參數、外部訪問、內部行為等等。在編寫目標單元之前通過開發Test Case,可以對需要考慮的這些因素有更好的了解,這樣編寫目標模塊與其他方法相比速度會更快,代碼的質量也會更好。
每當開發團隊需要發布新版本的時候,都要進行徹底的單元測試。所有的單元必須通過單元測試,這樣就可以發布成功的版本。如果有1個或以上的單元沒有通過所有的測試,Bug就出現了。遇到這種情況就需要在進行測試,如果需要的話還需要增加新的Test Case,檢查可以使Bug再現的所有情況。如果新的Test Case可以使Bug重現,就可以修正這個Bug,然后再進行測試,如果模塊通過了測試,就可以認為Bug已經修正,可以發布新的無Bug版本了。
為每一個發現的Bug添加新的Test Case是很有必要的,因為Bug會反復出現,當其重復出現時需要有效的測試來檢測Bug。這樣的話,Test Bettery會逐漸膨脹直至覆蓋所有的歷史Bug和潛在的錯誤。
測試工具:
有兩個小伙子,一個叫Kent Beck,另一個叫Eric Gamma,他們寫了一系列的Java類,希望可以把測試做的盡可能自動化,并稱之為JUnit,JUnit使整個單元測試界產生的很大的震動。其他的開發者們把JUnit的代碼移植到其他語言上,構建了一大系列稱為xUnit框架的產品。其總包括C/C++的CUnit和CPPUnit,Delphi的DUnit,Visual Basic的VBUnit,.NET平臺上的NUnit,等等。
所有這些框架都采用同樣的規則,對語言的依賴性很小,熟悉其中一個框架就能夠熟練應用其他框架。
下面要講的是如何通過使用CPPUnit來編寫測試代碼并提高單元的質量。
CPPUnit采用面向對象的編程方法,中間會遇到諸如封裝、繼承、多態這些概念。另外,CPPUnit采用C++ SEH(Structured Exception Handling),所以還會遇到異常的概念,以及throw, try, finally, catch這些指令。
CPPUnit
每一個Test Case都需要在TestCase類的派生類中定義。TestCase類中包含了許多基本的功能,比如運行測試、在Test Suite中注冊Test Case等。
比如在需要寫一個在磁盤上存儲數據的小模塊的時候,模塊(定義為DiskData類)主要實現兩個功能:讀取數據和裝載數據。例程如下:
typedef struct _DATA
{
??? int number;
??? char string[256];
}DATA, *LPDATA;

class DiskData
{
public:
??? DiskData();
??? ~DiskData();

??? LPDATA getData();
??? void setData(LPDATA value);

??? bool load(char *filename);
??? bool store(char *filename);

private:
??? DATA m_data;
};

此時,首先要做的事情不是弄明白上面的代碼是如何變出來的,而是要確定上面所定義的類是否完成了設計的全部功能——正確地讀取和存儲數據。

為此,需要設計一個新的Test Suite,其中包含兩個Test Case:一個讀取數據、一個存儲數據。

使用CPPUnit

最新版本的CPPUnit可以在http://cppunit.sourceforge.net/上免費下載到,其中包含所有的庫文件、文檔、例子程序和其他有趣的素材。

在Win32環境下,可以在VC++(6.0或更新版本)中使用CPPUnit,由于CPPUnit采用的是ANSI C++,所以可應用于C++ Builder等開發環境中的版本較少。
構建庫文件的步驟可以在CPPUnit發布版本的INSTALL-WIN32.txt文件中找到。構
建好庫文件之后就可以著手編寫Test Suite了。

在VC++下編寫單元測試程序的步驟如下:
?創建一個基于MFC的對話框應用程序(或者文檔應用程序)
?開啟RTTI:Project Settings -> C++ -> C++ Language
?在include目錄中加入CPPUnit\include:Tools -> Options -> Directories -> Include
?連接cppunitd.lib(靜態連接)或者cppunitd_dll.lib(動態連接),testrunnerd.lib。如果是在“Release”配置下編譯,同樣需要連接這些庫文件,只是需要把名稱中的“d”字母去掉。
?拷貝testrunnerd.dll文件到可執行文件夾的下面(或者路徑下的其他文件夾中),如果是動態連接的話,還需要拷貝cppunitd_dll.dll(“Release”配置下需要拷貝testrunner.dll和cppunit_dll.dll)。

配置好之后即可以著手進行單元測試類編碼了。

待測試的DiskData類,主要實現兩個功能:讀取和存儲磁盤上的數據。要測試這兩個功能,需要兩個Test Case:一個負責讀取數據、一個負責存儲數據。
下面是單元測試類的定義:
#if !defined(DISKDATA_TESTCASE_H_INCLUDED)
#define DISKDATA_TESTCASE_H_INCLUDED

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <cppunit/TestCase.h>//為了從基類TestCase派生新的測試類
#include <cppunit/extensions/HelperMacros.h>//方便快速定義測試類的宏

#include "DiskData.h"

class DiskDataTestCase : public CppUnit::TestCase
{
??? CPPUNIT_TEST_SUITE(DiskDataTestCase);//定義Test Suite的起點
?CPPUNIT_TEST(loadTest);//定義Test Case
?CPPUNIT_TEST(storeTest);
??? CPPUNIT_TEST_SUITE_END();//定義Test Suite的終點

public:
??? void setUp();
??? void tearDown();

protected:
??? void loadTest();
??? void storeTest();

private:
??? DiskData *fixture;
};

#endif

例程中,DiskDataTestCase類重載了兩個方法:setUp()和tearDown()。這兩個方法在Test Case開始和結束的時候自動運行。

測試邏輯是在兩個Protected方法中實現的,稍后要涉及到如何為測試邏輯編碼。?

例程的最后定義了指向DiskData類型數據的指針fixture,用以保存測試過程中的目標對象。setUp()是初始化函數,在調用每一個Test Case之前調用setUp(),同時負責初始化目標對象。Test Case運行過程中要使用fixture。在每一個Test Case運行結束之后,調用tearDown()銷毀fixture。這樣,每次運行Test Case時所使用的都是新產生的fixture。

測試步驟如下:
?開啟測試程序
?點擊“Run”按鍵
?調用setUp()方法:初始化fixture
?調用第一個Test Case函數
?調用tearDown()方法:釋放fixture
?調用setUp()方法:初始化fixture
?調用第二個Test Case函數
?調用tearDown()方法:釋放fixture?
?...

經過編碼:
#include "DiskDataTestCase.h"

CPPUNIT_TEST_SUITE_REGISTRATION(DiskDataTestCase);


void DiskDataTestCase::setUp()
{
??? fixture = new DiskData();
}

void DiskDataTestCase::tearDown()
{
??? delete fixture;
??? fixture = NULL;
}


void DiskDataTestCase::loadTest()
{
??? // our load test logic
}


void DiskDataTestCase::storeTest()
{
??? // our store test logic
}

現在,編碼已經變得非常簡單了:setUp()和tearDown()實現了創建、釋放fixture,下面要做的就是為loadTest()、storeTest()編碼了。

Test Case編碼

搞清楚需要測試那些方面之后的工作是編碼實現。可以通過使用庫函數、第三方庫函數、Win32 API或者C/C++操作符和指令的內部屬性。

有時需要輔助的文件或者數據庫表來存儲正確的數據。在本例中,通過對比內部不數據和外部文件的數據來判斷結果是否正確。

當出現錯誤時(比如內部數據和外部數據不同),需要拋出異常。可以通過CPPUNIT_FAIL(message)宏實現,也可以通過assertions宏實現。
以下是一些常用的assertion宏:
?CPPUNIT_ASSERT(condition): 檢查condition,如為false,拋出異常
?CPPUNIT_ASSERT_MESSAGE(message, condition): 檢查condition,如為false,拋出異常,并顯示預先設定的信息
?CPPUNIT_ASSERT_EQUAL(expected,current): 檢查expected與current的值是否相等,拋出異常,顯示expected和current的值
?CPPUNIT_ASSERT_EQUAL_MESSAGE(message,expected,current): 檢查expected的值與actual的值是否相等,拋出異常,顯示expected,current的值,并顯示預先設定的信息
?CPPUNIT_ASSERT_DOUBLES_EQUAL(expected,current,delta): 檢查expected, current之差是否小于delta,如果不小于,顯示expected和current的值

下面講一下loadTest編碼的編碼構想:首先需要一個外部文件,其中存儲這一個DATA型數據,文件的創建方式并不重要,關鍵是要保證里面的數據的正確性。然后,要進行的操作是檢查load函數從外部文件中讀出的數據和實現存在其中的數據是否一致。代碼如下:
//
// 前提:外部文件中已存儲了正確的數據。
//
#define AUX_FILENAME??? "ok_data.dat"
#define FILE_NUMBER??? 19
#define FILE_STRING??? "this is correct text stored in auxiliar file"

void DiskDataTestCase::loadTest()
{
??? // 相對路徑轉化為絕對路徑
??? TCHAR??? absoluteFilename[MAX_PATH];
??? DWORD??? size = MAX_PATH;

??? strcpy(absoluteFilename, AUX_FILENAME);
??? CPPUNIT_ASSERT( RelativeToAbsolutePath(absoluteFilename, &size) );

??? // 執行操作
??? CPPUNIT_ASSERT( fixture->load(absoluteFilename) );

??? // 通過assertion檢查運行結果
??? LPDATA??? loadedData = fixture->getData();

??? CPPUNIT_ASSERT(loadedData != NULL);
??? CPPUNIT_ASSERT_EQUAL(FILE_NUMBER, loadedData->number);
??? CPPUNIT_ASSERT( 0 == strcmp(FILE_STRING,
??????????? fixture->getData()->string) );
}

通過這樣一個簡單的Test Case測試了4個可能存在的錯誤:
?load函數返回值
?getData函數返回值
?number結構的成員值
?string結構的成員值
?
storeTest要復雜一些,因為需要把fixture中的數據存儲到臨時文件中,之后打開兩個文件(新的臨時文件和外部文件),讀出數據并比照內容。代碼如下:

void DiskDataTestCase::storeTest()
{
??? DATA??? d;
??? DWORD?? tmpSize, auxSize;
??? BYTE??? *tmpBuff, *auxBuff;
??? TCHAR?? absoluteFilename[MAX_PATH];
??? DWORD?? size = MAX_PATH;

??? // 填充結構體
??? d.number = FILE_NUMBER;
??? strcpy(d.string, FILE_STRING);

??? // 相對路徑轉化為絕對路徑

??? strcpy(absoluteFilename, AUX_FILENAME);
??? CPPUNIT_ASSERT( RelativeToAbsolutePath(absoluteFilename, &size) );

??? // 執行操作
??? fixture->setData(&d);
??? CPPUNIT_ASSERT( fixture->store("data.tmp") );

??? // 讀出兩文件的內容并對比
??? // ReadAllFileInMemory 是一個分配緩沖區的外部函數
??? // 把文件內容存入其中. 調用函數負責釋放緩沖區.
??? tmpSize = ReadAllFileInMemory("data.tmp", tmpBuff);
??? auxSize = ReadAllFileInMemory(absoluteFilename, auxBuff);

??? // 文件不存在則拋出異常
??? CPPUNIT_ASSERT_MESSAGE("New file doesn't exists?", tmpSize > 0);
??? CPPUNIT_ASSERT_MESSAGE("Aux file doesn't exists?", auxSize > 0);

??? // 文件大小可獲得,否則拋出異常
??? CPPUNIT_ASSERT(tmpSize != 0xFFFFFFFF);
??? CPPUNIT_ASSERT(auxSize != 0xFFFFFFFF);

??? // 緩沖區必須可用,否則拋出異常
??? CPPUNIT_ASSERT(tmpBuff != NULL);
??? CPPUNIT_ASSERT(auxBuff != NULL);

??? // 兩個文件的大小必須和DATA一致
??? CPPUNIT_ASSERT_EQUAL((DWORD) sizeof(DATA), tmpSize);
??? CPPUNIT_ASSERT_EQUAL(auxSize, tmpSize);

??? // 兩文件的內容必須一致
??? CPPUNIT_ASSERT( 0 == memcmp(tmpBuff, auxBuff, sizeof(DATA)) );

??? delete [] tmpBuff;
??? delete [] auxBuff;

??? ::DeleteFile("data.tmp");
}

啟動用戶界面
最后,看看如何顯示基于MFC的用戶界面對話框(事先在其內部編譯了TestRunner.dll)。

打開實現類的文件(ProjectNameApp.cpp),把下列代碼復制到InitInstance方法中:
#include <cppunit/ui/mfc/TestRunner.h>
#include <cppunit/extensions/TestFactoryRegistry.h>

BOOL CMy_TestsApp::InitInstance()
{
??? ....

??? // 聲明Test Runner,用以注冊的測試填入其中,并運行
??? CppUnit::MfcUi::TestRunner runner;

??? runner.addTest( CppUnit::TestFactoryRegistry::getRegistry().makeTest() );

??? runner.run();???

??? return TRUE;
}
?
很簡單,不是嗎?只需要定義一個"runner"實例,添加注冊過的test(test是通過CPP文件中的CPPUNIT_TEST_SUITE_REGISTRATION宏注冊的),就可以運行run函數了。

編譯、運行,開始你的單元測試吧:)

?

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国产一区二区三区无遮挡| 国一区二区在线观看| 亚洲欧美视频| 香蕉免费一区二区三区在线观看| 一本一本久久| 中文精品视频| 韩国av一区| 麻豆亚洲精品| 美女脱光内衣内裤视频久久网站| 美女任你摸久久| 欧美大片免费| 一本久久综合亚洲鲁鲁| 亚洲欧美日韩另类| 免费成人网www| 欧美三区在线| 国产一区二区剧情av在线| 好吊色欧美一区二区三区视频| 国产亚洲一区精品| 亚洲电影下载| 午夜精品久久久久久久蜜桃app| 亚洲欧美精品在线| 麻豆av福利av久久av| 亚洲精品久久嫩草网站秘色| 亚洲欧洲精品成人久久奇米网 | 国产综合香蕉五月婷在线| 国产视频精品va久久久久久| 亚洲黄色影片| 欧美在线观看网址综合| 亚洲国产精品ⅴa在线观看| 亚洲网站在线观看| 欧美 日韩 国产一区二区在线视频 | 久久久亚洲欧洲日产国码αv| 欧美激情精品久久久久久变态| 国产精品久久久久久久久久久久| 国产欧美一区二区精品仙草咪| 亚洲精品一区二区在线观看| 久久精品视频99| 亚洲乱码国产乱码精品精98午夜| 欧美在线一二三区| 欧美私人啪啪vps| 亚洲欧洲综合另类在线| 久久久99精品免费观看不卡| 久久精品二区三区| 中文网丁香综合网| 欧美日韩一区自拍| 91久久线看在观草草青青| 欧美在线看片| 亚洲性视频h| 欧美日韩国产色视频| 在线日韩中文字幕| 美女网站久久| 老**午夜毛片一区二区三区| 国模精品一区二区三区| 欧美主播一区二区三区美女 久久精品人 | 久久网站热最新地址| 亚洲精品一二三| 麻豆精品在线视频| 欧美一级电影久久| 国产日韩精品入口| 欧美在线观看你懂的| 一区二区三区高清不卡| 欧美日韩精品欧美日韩精品一| 日韩视频在线一区| 亚洲三级电影在线观看| 欧美日韩成人一区| 日韩一区二区精品| 日韩视频在线观看国产| 国产精品夫妻自拍| 欧美中文字幕在线观看| 亚洲主播在线观看| 狠狠色综合一区二区| 久久夜色精品国产噜噜av| 欧美一区二区三区四区在线| 国产一区二区黄| 欧美.日韩.国产.一区.二区| 久久精品欧洲| 亚洲国产99精品国自产| 亚洲福利视频一区二区| 久久夜色精品国产噜噜av| 亚洲激情专区| 亚洲精品乱码久久久久久蜜桃91| 欧美性jizz18性欧美| 亚洲欧美日本视频在线观看| 亚洲欧美视频一区| 激情文学综合丁香| 亚洲电影在线播放| 欧美性大战久久久久| 午夜国产精品视频免费体验区| 性欧美8khd高清极品| 一区二区亚洲欧洲国产日韩| 久久婷婷国产综合精品青草| 久久久久高清| 亚洲伦理在线观看| 亚洲欧美一区二区激情| 亚洲国产精品传媒在线观看| 亚洲高清一二三区| 国产精品一区久久久| 欧美国产极速在线| 欧美午夜视频网站| 欧美大片第1页| 国产美女精品在线| 欧美激情精品久久久久久| 欧美日韩亚洲一区二区| 久久久久成人精品免费播放动漫| 久久久人人人| 亚洲三级免费| 久久久亚洲国产天美传媒修理工 | 亚洲精品小视频在线观看| 欧美色区777第一页| 久久久久久综合网天天| 欧美日本高清| 老司机久久99久久精品播放免费 | 麻豆91精品91久久久的内涵| 欧美精品国产一区二区| 久久婷婷成人综合色| 国产精品欧美激情| 亚洲人成在线观看一区二区| 国内一区二区三区| 亚洲视频在线看| 亚洲国产aⅴ天堂久久| 亚洲欧美久久久久一区二区三区| 日韩网站在线观看| 久久夜色精品| 巨乳诱惑日韩免费av| 国产精品国产三级国产aⅴ9色| 欧美激情性爽国产精品17p| 国产亚洲精品综合一区91| 亚洲午夜未删减在线观看| 亚洲区一区二| 亚洲一区二区在线免费观看| 亚洲精选视频在线| 久久久久久日产精品| 久久久久久久久久久久久女国产乱| 欧美午夜精品伦理| 亚洲精品影视| 一区二区三区欧美日韩| 欧美电影免费观看高清完整版| 巨乳诱惑日韩免费av| 国产欧美日韩| 久久成人资源| 麻豆国产精品一区二区三区| 国产一区91精品张津瑜| 久久国产精品久久w女人spa| 欧美一区二视频在线免费观看| 国产精品稀缺呦系列在线| 亚洲欧美清纯在线制服| 亚洲午夜电影在线观看| 国产精品视频| 久久国产精品一区二区三区四区| 久久精品国产第一区二区三区| 国产又爽又黄的激情精品视频| 亚洲午夜一区二区| 欧美在线3区| 国内精品久久久久影院优| 欧美一区二区在线| 亚洲欧美日韩国产另类专区| 亚洲欧美日韩精品综合在线观看| 国产精品美女久久久久久2018| 一区二区欧美在线观看| 亚洲一区区二区| 黑丝一区二区三区| 欧美 日韩 国产 一区| 亚洲精品久久久久久久久久久久| 亚洲午夜一区二区| 国产在线视频欧美一区二区三区| 久久综合九色综合欧美狠狠| 亚洲精品在线视频观看| 久久精品一本| 亚洲精品一区二区三区不| 国产精品久久久999| 久久久久中文| 夜夜爽av福利精品导航| 久久亚洲图片| 亚洲欧美日韩在线不卡| 亚洲国产高清在线观看视频| 国产精品国产亚洲精品看不卡15| 欧美在线视频免费播放| 亚洲精品美女久久7777777| 欧美在线欧美在线| 亚洲精品国产精品久久清纯直播| 一本色道久久88精品综合| 99成人在线| 国产精品一区二区你懂的| 蜜乳av另类精品一区二区| 日韩亚洲视频| 欧美成人综合一区| 久久久久久噜噜噜久久久精品 | 中文av一区特黄| 国内精品久久久久影院薰衣草| 欧美日韩在线播放三区| 每日更新成人在线视频| 午夜精品一区二区三区在线视 | 亚洲蜜桃精久久久久久久 | 一本久久a久久免费精品不卡| 久久这里只有精品视频首页| 亚洲在线观看视频| 一区二区av| 日韩视频一区二区在线观看| 国产一区二区丝袜高跟鞋图片| 国产精品成人免费视频|