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

隨筆-60  評(píng)論-98  文章-0  trackbacks-0

用CPPUnit做單元測(cè)試
例子程序下載:http://www.codeproject.com/library/Using_CPPUnit/my_tests.zip
CPPUnit最新版本免費(fèi)下載:
http://cppunit.sourceforge.net/
CPPUnit是基于C++的單元測(cè)試框架,可以有效提高開發(fā)的系統(tǒng)質(zhì)量。
引言:
QA過程常采用兩種測(cè)試方法:
1、單元測(cè)試(acceptance測(cè)試):為軟件系統(tǒng)中的每一個(gè)邏輯單元制定的一系列驗(yàn)證方法。僅測(cè)試單元的功能,而不考慮各個(gè)單元之間的協(xié)作關(guān)系。
2、系統(tǒng)測(cè)試(集成測(cè)試):測(cè)試系統(tǒng)的功能,尤其是各單元模塊之間的協(xié)作關(guān)系。
下面要講的是如何采用CPPUnit對(duì)C/C++工程進(jìn)行單元測(cè)試。
文章假設(shè)讀者熟悉單元測(cè)試的概念及其重要性。
單元測(cè)試設(shè)計(jì):
想一下開發(fā)團(tuán)隊(duì)中常常出現(xiàn)的一種場(chǎng)景:程序員正在使用Debugger工具測(cè)試代碼。采用Debugger工具可以可以隨時(shí)隨地檢查每個(gè)變量。步步跟蹤,檢查變量的值是否異常。Debugger是一種強(qiáng)有力的調(diào)試工具,但是調(diào)試速度相當(dāng)慢,并且包含不少錯(cuò)誤。在這種情況下調(diào)試是讓人崩潰的。這些復(fù)雜有大量重復(fù)的驗(yàn)證方法是可以通過自動(dòng)化的手段完成的,需要做的是選擇合適的工具并編寫少量代碼。
下面要介紹的工具叫做“單元測(cè)試框架”,借助這種工具,可以通過編寫一些小的模塊來(lái)完成模塊(可以是類、函數(shù)和庫(kù))的單元測(cè)試。
下面來(lái)看一個(gè)例子:編寫一個(gè)小的模塊,主要功能是求兩數(shù)之和。其C語(yǔ)言代碼如下:
BOOL addition(int a, int b)
{
    return (a + b);
}
測(cè)試單元編寫成另外一個(gè)模塊(C函數(shù))。該模塊測(cè)試所有可能的求兩數(shù)之和的組合,通過返回True或False來(lái)判斷被測(cè)模塊是否通過了測(cè)試。代碼如下:
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);
}
測(cè)試的情況包括:
正數(shù)+正數(shù)
0+0
正數(shù)+0
負(fù)數(shù)+0
正數(shù)+負(fù)數(shù)
負(fù)數(shù)+正數(shù)
負(fù)數(shù)+負(fù)數(shù)
每一次測(cè)試都是通過對(duì)比被測(cè)模塊的返回值和期望值,如果二者不同,返回FALSE。如果最終返回TRUE,說(shuō)明模塊通過了所有的測(cè)試。
這個(gè)用以測(cè)試其他模塊的小模塊(函數(shù))被稱為Test Case, 其中包含了程序員需要對(duì)被測(cè)單元的一系列檢查。每一個(gè)確認(rèn)(對(duì)被測(cè)單元的一次調(diào)用)都必須和被測(cè)單元相對(duì)應(yīng)。在這個(gè)例子中,檢查了“求和操作”在操作數(shù)符號(hào)不同的情況下的運(yùn)行情況。當(dāng)然了,還需要另外寫一些Test Case來(lái)驗(yàn)證其他情況下的運(yùn)行情況。比如其他一些常見的加法組合。例子如下:
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);
}
上面的例子測(cè)試了多個(gè)數(shù)據(jù)相加順序不同的情況。
上述的兩個(gè)Test Case組成了一個(gè)Test Suite,Test Suite是指用來(lái)測(cè)試同一被測(cè)單元的一組Test Case。
在開發(fā)被測(cè)模塊時(shí)必須同時(shí)編寫這些Test Case和Test Suite的代碼,被測(cè)模塊變更時(shí),要同時(shí)變更(有時(shí)需要增加)相應(yīng)的Test Case和Test Suite。
舉例來(lái)說(shuō),當(dāng)求和模塊升級(jí)為可以對(duì)小數(shù)求和的模塊,就必須變更Test Case和Test Suite,加入諸如addDecimalNumbersTest之類的Test Case。
極限編程建議程序員在編寫目標(biāo)模塊之前就開發(fā)出所有單元測(cè)試中要用到的Test Case。其主要理由是:一旦程序員處于開發(fā)過程之中,那么他就進(jìn)入了一個(gè)持續(xù)改進(jìn)的階段,必須同時(shí)考慮單元模塊功能、需要公布的接口、需要給方法傳遞的參數(shù)、外部訪問、內(nèi)部行為等等。在編寫目標(biāo)單元之前通過開發(fā)Test Case,可以對(duì)需要考慮的這些因素有更好的了解,這樣編寫目標(biāo)模塊與其他方法相比速度會(huì)更快,代碼的質(zhì)量也會(huì)更好。
每當(dāng)開發(fā)團(tuán)隊(duì)需要發(fā)布新版本的時(shí)候,都要進(jìn)行徹底的單元測(cè)試。所有的單元必須通過單元測(cè)試,這樣就可以發(fā)布成功的版本。如果有1個(gè)或以上的單元沒有通過所有的測(cè)試,Bug就出現(xiàn)了。遇到這種情況就需要在進(jìn)行測(cè)試,如果需要的話還需要增加新的Test Case,檢查可以使Bug再現(xiàn)的所有情況。如果新的Test Case可以使Bug重現(xiàn),就可以修正這個(gè)Bug,然后再進(jìn)行測(cè)試,如果模塊通過了測(cè)試,就可以認(rèn)為Bug已經(jīng)修正,可以發(fā)布新的無(wú)Bug版本了。
為每一個(gè)發(fā)現(xiàn)的Bug添加新的Test Case是很有必要的,因?yàn)锽ug會(huì)反復(fù)出現(xiàn),當(dāng)其重復(fù)出現(xiàn)時(shí)需要有效的測(cè)試來(lái)檢測(cè)Bug。這樣的話,Test Bettery會(huì)逐漸膨脹直至覆蓋所有的歷史Bug和潛在的錯(cuò)誤。
測(cè)試工具:
有兩個(gè)小伙子,一個(gè)叫Kent Beck,另一個(gè)叫Eric Gamma,他們寫了一系列的Java類,希望可以把測(cè)試做的盡可能自動(dòng)化,并稱之為JUnit,JUnit使整個(gè)單元測(cè)試界產(chǎn)生的很大的震動(dòng)。其他的開發(fā)者們把JUnit的代碼移植到其他語(yǔ)言上,構(gòu)建了一大系列稱為xUnit框架的產(chǎn)品。其總包括C/C++的CUnit和CPPUnit,Delphi的DUnit,Visual Basic的VBUnit,.NET平臺(tái)上的NUnit,等等。
所有這些框架都采用同樣的規(guī)則,對(duì)語(yǔ)言的依賴性很小,熟悉其中一個(gè)框架就能夠熟練應(yīng)用其他框架。
下面要講的是如何通過使用CPPUnit來(lái)編寫測(cè)試代碼并提高單元的質(zhì)量。
CPPUnit采用面向?qū)ο蟮木幊谭椒?,中間會(huì)遇到諸如封裝、繼承、多態(tài)這些概念。另外,CPPUnit采用C++ SEH(Structured Exception Handling),所以還會(huì)遇到異常的概念,以及throw, try, finally, catch這些指令。
CPPUnit
每一個(gè)Test Case都需要在TestCase類的派生類中定義。TestCase類中包含了許多基本的功能,比如運(yùn)行測(cè)試、在Test Suite中注冊(cè)Test Case等。
比如在需要寫一個(gè)在磁盤上存儲(chǔ)數(shù)據(jù)的小模塊的時(shí)候,模塊(定義為DiskData類)主要實(shí)現(xiàn)兩個(gè)功能:讀取數(shù)據(jù)和裝載數(shù)據(jù)。例程如下:
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;
};

此時(shí),首先要做的事情不是弄明白上面的代碼是如何變出來(lái)的,而是要確定上面所定義的類是否完成了設(shè)計(jì)的全部功能——正確地讀取和存儲(chǔ)數(shù)據(jù)。

為此,需要設(shè)計(jì)一個(gè)新的Test Suite,其中包含兩個(gè)Test Case:一個(gè)讀取數(shù)據(jù)、一個(gè)存儲(chǔ)數(shù)據(jù)。

使用CPPUnit

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

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

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

配置好之后即可以著手進(jìn)行單元測(cè)試類編碼了。

待測(cè)試的DiskData類,主要實(shí)現(xiàn)兩個(gè)功能:讀取和存儲(chǔ)磁盤上的數(shù)據(jù)。要測(cè)試這兩個(gè)功能,需要兩個(gè)Test Case:一個(gè)負(fù)責(zé)讀取數(shù)據(jù)、一個(gè)負(fù)責(zé)存儲(chǔ)數(shù)據(jù)。
下面是單元測(cè)試類的定義:
#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派生新的測(cè)試類
#include <cppunit/extensions/HelperMacros.h>//方便快速定義測(cè)試類的宏

#include "DiskData.h"

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

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

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

private:
    DiskData *fixture;
};

#endif

例程中,DiskDataTestCase類重載了兩個(gè)方法:setUp()和tearDown()。這兩個(gè)方法在Test Case開始和結(jié)束的時(shí)候自動(dòng)運(yùn)行。

測(cè)試邏輯是在兩個(gè)Protected方法中實(shí)現(xiàn)的,稍后要涉及到如何為測(cè)試邏輯編碼。 

例程的最后定義了指向DiskData類型數(shù)據(jù)的指針fixture,用以保存測(cè)試過程中的目標(biāo)對(duì)象。setUp()是初始化函數(shù),在調(diào)用每一個(gè)Test Case之前調(diào)用setUp(),同時(shí)負(fù)責(zé)初始化目標(biāo)對(duì)象。Test Case運(yùn)行過程中要使用fixture。在每一個(gè)Test Case運(yùn)行結(jié)束之后,調(diào)用tearDown()銷毀fixture。這樣,每次運(yùn)行Test Case時(shí)所使用的都是新產(chǎn)生的fixture。

測(cè)試步驟如下:
 開啟測(cè)試程序
 點(diǎn)擊“Run”按鍵
 調(diào)用setUp()方法:初始化fixture
 調(diào)用第一個(gè)Test Case函數(shù)
 調(diào)用tearDown()方法:釋放fixture
 調(diào)用setUp()方法:初始化fixture
 調(diào)用第二個(gè)Test Case函數(shù)
 調(diào)用tearDown()方法:釋放fixture 
 ...

經(jīng)過編碼:
#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
}

現(xiàn)在,編碼已經(jīng)變得非常簡(jiǎn)單了:setUp()和tearDown()實(shí)現(xiàn)了創(chuàng)建、釋放fixture,下面要做的就是為loadTest()、storeTest()編碼了。

Test Case編碼

搞清楚需要測(cè)試那些方面之后的工作是編碼實(shí)現(xiàn)??梢酝ㄟ^使用庫(kù)函數(shù)、第三方庫(kù)函數(shù)、Win32 API或者C/C++操作符和指令的內(nèi)部屬性。

有時(shí)需要輔助的文件或者數(shù)據(jù)庫(kù)表來(lái)存儲(chǔ)正確的數(shù)據(jù)。在本例中,通過對(duì)比內(nèi)部不數(shù)據(jù)和外部文件的數(shù)據(jù)來(lái)判斷結(jié)果是否正確。

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

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

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

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

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

    // 通過assertion檢查運(yùn)行結(jié)果
    LPDATA    loadedData = fixture->getData();

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

通過這樣一個(gè)簡(jiǎn)單的Test Case測(cè)試了4個(gè)可能存在的錯(cuò)誤:
 load函數(shù)返回值
 getData函數(shù)返回值
 number結(jié)構(gòu)的成員值
 string結(jié)構(gòu)的成員值
 
storeTest要復(fù)雜一些,因?yàn)樾枰裦ixture中的數(shù)據(jù)存儲(chǔ)到臨時(shí)文件中,之后打開兩個(gè)文件(新的臨時(shí)文件和外部文件),讀出數(shù)據(jù)并比照內(nèi)容。代碼如下:

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

    // 填充結(jié)構(gòu)體
    d.number = FILE_NUMBER;
    strcpy(d.string, FILE_STRING);

    // 相對(duì)路徑轉(zhuǎn)化為絕對(duì)路徑

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

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

    // 讀出兩文件的內(nèi)容并對(duì)比
    // ReadAllFileInMemory 是一個(gè)分配緩沖區(qū)的外部函數(shù)
    // 把文件內(nèi)容存入其中. 調(diào)用函數(shù)負(fù)責(zé)釋放緩沖區(qū).
    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);

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

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

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

    delete [] tmpBuff;
    delete [] auxBuff;

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

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

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

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

    // 聲明Test Runner,用以注冊(cè)的測(cè)試填入其中,并運(yùn)行
    CppUnit::MfcUi::TestRunner runner;

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

    runner.run();   

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

編譯、運(yùn)行,開始你的單元測(cè)試吧:)

posted on 2007-05-26 10:53 創(chuàng)建更好的解決方案 閱讀(2854) 評(píng)論(4)  編輯 收藏 引用 所屬分類: CPPUnit專欄

評(píng)論:
# re: 用CPPUnit做單元測(cè)試(原文在E文全翻中) 2007-09-03 17:28 | seu
不錯(cuò)  回復(fù)  更多評(píng)論
  
# re: 用CPPUnit做單元測(cè)試(原文在E文全翻中) 2007-12-24 08:42 | FongLuo
有時(shí)間一定要用用。  回復(fù)  更多評(píng)論
  
# re: 用CPPUnit做單元測(cè)試(原文在E文全翻中) 2008-10-15 17:16 | 浪跡天涯
這和自己寫測(cè)試代碼有什么最大的好處???
剛學(xué)cppunit,不是很明白,感覺還不如自己寫測(cè)試代碼來(lái)的快!  回復(fù)  更多評(píng)論
  
# re: 用CPPUnit做單元測(cè)試(原文在E文全翻中) 2008-10-22 11:36 | 陳勇
謝謝啦,很有用?。。。。。。。。。。?!  回復(fù)  更多評(píng)論
  

只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲电影免费在线观看| 亚洲激情不卡| 国产欧美视频一区二区| 亚洲性感美女99在线| 亚洲麻豆国产自偷在线| 欧美了一区在线观看| 亚洲人成精品久久久久| 9人人澡人人爽人人精品| 欧美福利视频网站| 亚洲黄色在线视频| 一区二区三区高清| 欧美亚洲不卡| 性高湖久久久久久久久| 久久国产直播| 亚洲国产精品va在看黑人| 鲁大师影院一区二区三区| 亚洲国产高清在线| 中国成人亚色综合网站| 国产精品视频最多的网站| 欧美一区二区免费视频| 裸体素人女欧美日韩| 国内精品嫩模av私拍在线观看 | 欧美日韩在线视频首页| 在线综合亚洲| 久久久蜜桃一区二区人| 亚洲福利视频一区| 欧美视频中文在线看| 亚洲欧美卡通另类91av| 久久综合久久综合九色| 亚洲乱码精品一二三四区日韩在线| 欧美日产在线观看| 亚洲一区二区三区午夜| 久久综合色婷婷| 一区二区免费看| 国产一区二区三区的电影| 欧美va天堂| 亚洲作爱视频| 老司机aⅴ在线精品导航| 亚洲精品日韩精品| 国产精品羞羞答答| 狂野欧美激情性xxxx| 亚洲精品1区2区| 久久爱91午夜羞羞| 亚洲美女黄色| 国产一区二区三区四区| 欧美日本久久| 久久青草福利网站| 99在线热播精品免费| 六十路精品视频| 亚洲免费在线精品一区| 亚洲国产高清在线| 国产乱肥老妇国产一区二 | 欧美一区二区在线看| 亚洲激情影视| 亚洲欧美一区二区三区极速播放 | 亚洲日本成人网| 国产三级精品三级| 欧美精品在欧美一区二区少妇| 亚洲欧美日韩系列| 日韩午夜黄色| 欧美大片在线观看一区二区| 午夜国产精品影院在线观看| 亚洲精品少妇网址| 好吊色欧美一区二区三区视频| 欧美日韩综合在线| 欧美国产日韩在线| 久久亚洲图片| 欧美一区中文字幕| 亚洲一卡二卡三卡四卡五卡| 亚洲精品国产品国语在线app| 久久亚洲精品网站| 欧美亚洲一区二区三区| 亚洲人体偷拍| 在线日韩av| 国产精品日日摸夜夜添夜夜av | 麻豆成人在线播放| 欧美亚洲免费电影| 亚洲在线黄色| 亚洲网友自拍| 9l视频自拍蝌蚪9l视频成人| 亚洲国产高清aⅴ视频| 久久在线观看视频| 久久久久久网址| 久久er精品视频| 欧美一区二区在线免费播放| 亚洲午夜在线观看视频在线| 一区二区三区日韩精品| 99国产精品久久久久久久成人热| 亚洲人成在线免费观看| 尤妮丝一区二区裸体视频| 黑人巨大精品欧美一区二区小视频 | 中文在线不卡视频| 午夜视黄欧洲亚洲| 毛片精品免费在线观看| 欧美日韩精品欧美日韩精品| 国产精品美女久久福利网站| 国内偷自视频区视频综合| 亚洲夫妻自拍| 亚洲图片在线| 久久久久久自在自线| 亚洲国产精品va在看黑人| 亚洲欧洲在线一区| 亚洲一区在线播放| 久久久久久久网站| 欧美日韩精品一区| 国产一区二区三区无遮挡| 亚洲黄色片网站| 香蕉精品999视频一区二区| 美腿丝袜亚洲色图| 一区二区三区国产| 久久久久国产精品www| 欧美日韩免费观看一区=区三区| 国产一区二区三区久久悠悠色av| 亚洲精品五月天| 久久精品99国产精品酒店日本| 欧美国产欧美亚洲国产日韩mv天天看完整 | 暖暖成人免费视频| 国产精品99久久久久久久vr| 久久精彩免费视频| 欧美视频中文一区二区三区在线观看 | 亚洲午夜精品网| 美女网站久久| 国产一区二区高清| 一区二区三区产品免费精品久久75| 久久精品视频在线| 一本色道久久综合亚洲精品高清 | 久久久久久网站| 亚洲免费电影在线| 久久蜜桃精品| 国产日韩欧美精品在线| 一二三区精品福利视频| 欧美成人一品| 久久精品国产99| 国产精品日本一区二区| 一本一本a久久| 欧美福利视频网站| 久久精品99国产精品酒店日本| 国产精品日韩欧美一区二区| 在线视频日本亚洲性| 欧美激情中文字幕一区二区| 久久久精品一区| 国产亚洲激情在线| 欧美呦呦网站| 亚洲永久精品国产| 国产精品久久久久久亚洲毛片 | 欧美在线啊v一区| 一区二区三区回区在观看免费视频| 欧美高清视频一二三区| 亚洲激情电影在线| 欧美成人免费在线| 久久亚洲综合色一区二区三区| 国产一区二区视频在线观看| 欧美一区二区三区在线播放| 亚洲视频成人| 国产精品久久久久77777| 中日韩美女免费视频网址在线观看 | 在线亚洲+欧美+日本专区| 欧美日韩成人一区二区三区| 亚洲日本在线视频观看| 亚洲电影免费在线| 欧美成人国产va精品日本一级| 在线精品国产欧美| 毛片基地黄久久久久久天堂| 久久久国产精品一区| 玉米视频成人免费看| 美女任你摸久久| 蜜桃av噜噜一区| 亚洲精品一级| 日韩网站在线观看| 欧美午夜精品一区| 欧美一级免费视频| 欧美在线一级视频| 亚洲高清在线播放| 亚洲国产导航| 欧美视频一区二区三区在线观看| 亚洲一区二区视频| 小处雏高清一区二区三区| 国模私拍视频一区| 欧美激情亚洲国产| 欧美色区777第一页| 欧美亚洲一级| 久久频这里精品99香蕉| 日韩一二三在线视频播| 一本色道久久| 国产主播一区| 亚洲国产小视频在线观看| 欧美三级午夜理伦三级中文幕| 欧美一级成年大片在线观看| 久久国产精品一区二区三区四区| 亚洲国产精品t66y| 亚洲视频成人| 在线观看亚洲精品视频| 亚洲精品一区二区三区蜜桃久| 国产乱码精品一区二区三| 裸体丰满少妇做受久久99精品| 欧美日韩国产亚洲一区| 久久国产精品久久国产精品| 欧美大片在线观看一区| 午夜视频在线观看一区| 六月丁香综合|