• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
    • 軟件測試技術
    • 軟件測試博客
    • 軟件測試視頻
    • 開源軟件測試技術
    • 軟件測試論壇
    • 軟件測試沙龍
    • 軟件測試資料下載
    • 軟件測試雜志
    • 軟件測試人才招聘
      暫時沒有公告

    字號: | 推薦給好友 上一篇 | 下一篇

    單元測試作業指導書

    發布: 2007-5-05 18:57 | 作者: 網絡轉載 | 來源: 轉載 | 查看: 547次 | 進入軟件測試論壇討論

    領測軟件測試網 這是我以前任項目經理時,編寫的關于單元測試方面的作業指導書,針對多種開發環境敘述怎么進行單元測試以及環境配置,現在整理了一下。應該對大家有所幫助。

      這是第一部分,主要針對C和C++項目的(包括了Windows環境和Linux');" href="javascript:;" target=_self>Linux環境),下部分將針對Java及J2EE項目。

      1. 目的

      為了減少代碼中的錯誤數量, 減少調試所花的時間和精力, 改善軟件質量, 減少開發和維護的時間和成本。

      2. 適用范圍

      適用于C及C++的所有產品。

      3. 適用內容

      3.1 C++標準

      3.1.1測試環境使用Visual C++,Windows窗口應用程序

      3.1.1.1前題:使用CppUnit1.6.2版,解壓后,路徑為x:\\cppunit-1.6.2;

      在工程文件中配置測試框架使用環境:加入執行頭文件的路徑x:\\cppunit-1.6.2\include,加入導入庫文件的路徑x:\\cppunit-1.6.2\lib;

      配置DEBUG(測試)版環境:

      加入需要鏈接的靜態測試框模塊testrunnercd.lib(運行測試用例的選擇對話框)和cppunitcd.lib(測試框架);

      加入測試Add-ins,庫名為x:\\cppunit-1.6.2\lib\TestRunnerDSPlugInD.dll;

      在Project Settings/C++/C++ Language中啟用RTTI;

      3.1.1.2建立測試用例:

      1、以類名加前輟“Test”命名測試單元文件名,比如“CMabString”類的類文件名為MabString.cpp,則測試單元文件命名為TestMabString.cpp;

      2、加入測試框架頭文件以及要測試的單元頭文件,以TestMabString為例:

      頭文件:testmabstring.h
    #ifndef CPP_UNIT_TestNode_H
    #define CPP_UNIT_TestNode_H
    //包含測試框架的頭文件
    #include <cppunit/TestCase.h>
    #include <cppunit/extensions/HelperMacros.h>
    //包含被測試單元的頭文件
    #include "mabstring.h"
    //派生測試框架的測試用例類
    class TestMabString : public CppUnit::TestCase
    {
     //定義測試用例列表,此列表將出現在運行測試用例的選擇對話框中
     CPPUNIT_TEST_SUITE( TestMabString );
     CPPUNIT_TEST( FindByName );
     CPPUNIT_TEST_SUITE_END();

     protected:
     //
     CMabString m_MabStr;
     public:
      //用例初始化,可作為樁函數
      void setUp ();
      //用例析構
      void tearDown();
     protected:
      //測試用例
      void FindByName (void);
    };

    #endif

    類文件:testmabstring.cpp

    #include "TestMabString.h"
    #include "iostream.h"
    #include "strstrea.h"

    //注冊本測試單元

    CPPUNIT_TEST_SUITE_REGISTRATION( TestMabString );

    //定義測試用例

    void TestMabString::FindByName ()
    {
     //功能性測試,屬黑盒測試
     //normal test
     //條件及錯誤測試,屬白盒測試
     //extra test,
     //例外測試,屬白盒測試
     //exception test,

     bool bRet=false;
     try{
      //put the exception code here...
     }
     //catch(CXXX& e)
     catch(...)
     {
      bRet=true;
     }
     CPPUNIT_ASSERT(bRet);
     //由于并不能夠執行所有單元測試應該執行的路徑,比如CMabString是從CString
     //類中派生出來的,而可能CMabString中的Find只簡單調用了CString中的Find方法,//所以并不需要測試;
     //在此處說明所有不用測試的路徑;
     //other test, see the ...
    }

    void TestMabString::setUp ()
    {
     //開始測試前的初始代碼
     m_pNode=new Node();
    }

    void TestMabString::tearDown()
    {
     //測試結束代碼
     if(m_pNode)
      delete m_pNode;
    }

      3、在啟動程序中加入以下代碼,以便運行“測試用例選擇”對話框:
    #ifdef _DEBUG

    //包括測試頭文件

    #include <msvc6/testrunner/TestRunner.h>

    #include <cppunit/extensions/TestFactoryRegistry.h>

    static AFX_EXTENSION_MODULE extTestRunner;

    #endif



    //以下為測試代碼,此部分測試不會出現在發布版中

    #ifdef _DEBUG

    TestRunner runner;

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

    runner.run ();

    #endif

      4、制作發行版

      發行版需要做以下工作

      將Project的屬性設置為Release(這將自動去除_DEBUG的聲明);

      從工程項目中去掉測試文件(即帶有test前輟的文件);

      3.1.2測試環境使用Visual C++,Windows非窗口應用程序

      3.1.2.1前題:使用CppUnit1.6.2版,解壓后,路徑為x:\\cppunit-1.6.2;

      在工程文件中配置測試框架使用環境:加入執行頭文件的路徑x:\\cppunit-1.6.2\include,加入導入庫文件的路徑x:\\cppunit-1.6.2\lib;

      配置DEBUG(測試)版環境:

      加入需要鏈接的靜態測試框模塊cppunitcd.lib(測試框架);

      在Project Settings/C++/C++ Language中啟用RTTI;

      3.1.2.2建立測試用例:

      1、以類名加前輟“Test”命名測試單元文件名,比如“CMabString”類的類文件名為MabString.cpp,則測試單元文件命名為TestMabString.cpp;

      2、加入測試框架頭文件以及要測試的單元頭文件,以TestMabString為例:

      頭文件:testmabstring.h

      3、測試示例同上;

      3.2 C標準

      3.2.1測試環境使用gcc,Linux非窗口應用程序

      前題:使用check0.8.0版,解壓后,路徑為/xx/check-0.8.0;

      配置測試框架使用環境(我建議采用標準組織推薦的使用Autoconf和Automake來生成配置文件configure和Makefile,因為使用它們可以建立符合國際標準的configure腳本 和Makefile文件,并且可以有效的建立壓縮包和方便分發必需的文件(也方便在發行版中去除測試用例文件):

      l 首先需編寫configure.in文件,此文件用于Autoconf生成configure可執行腳本;configure.in的框架大致如下:

      dnl 此文件用于生成configure腳本,

      dnl AC_INIT的xxxx.h參數代表本目錄下一個有效的文件名

      AC_INIT(xxxx.h)

      dnl AM_INIT_AUTOMAKE的兩個參數分別是生成應用程序的版本及版本號,

      dnl 可能有些版本的Autoconf和Automake不支持此宏

      AM_INIT_AUTOMAKE(xxxx, x.x)

      dnl 以下為編譯依賴的檢測

      dnl Checks for programs.

      AC_PROG_AWK

      AC_PROG_CC

      AC_PROG_INSTALL

      AC_PROG_LN_S

      dnl Checks for libraries.

      AC_CHECK_LIB(check,suite_create)

      dnl Checks for header files.

      AM_CONFIG_HEADER(config.h)

      dnl Checks for typedefs, structures, and compiler characteristics.

      dnl Checks for library functions.

      dnl 將Automake生成的Makefile.in文件輸出為Makefile文件

      AC_OUTPUT(Makefile)

      (提示:autoscan可以生成configure.in文件的基本框架,但很基本,可其生成的configure.scan文件的基礎補充,然后更名為configure.in)

      l 編寫Makefile.am文件,用于Automake生成Makefile.in文件,Makefile.am文件的大致框架如下:(其中xxxx為應用程序文件名,比如program.c文件的測試程序文件名我建議為check_program.c;)

    TESTS = check_xxxx

    noinst_PROGRAMS=check_xxxx

    frame_path=xx/check-0.8.0

    xxxx_docs =\

    srcfilelist_1\

    srcfilelist_2\

    .......\

    .....

    xxxx_SOURCES=\

    srcfilelist_1\

    srcfilelist_2\

    .......

    EXTRA_DIST = $(xxxx_docs)
    INCLUDES = -I$(frame_path)/src -I$(other_path)/include

    LDADD= \$(frame_path)/src/libcheck.a

    CLEANFILES=*.*~

     。∕akefile.am有很許多標記,可以參閱相應文檔。但常用的如:noinst_PROGRAMS為生成的可執行文件,xxxx_SOURCES(應用程序名加后輟_SOURCES)為源文件列表,EXTRA_DIST為發布程序時不需要的文件列表(用此方法可以將測試文件去掉),INCLUDES為要包含的頭文件路徑,check的頭文件位置在其安裝目錄下的src中;LDADD為要鏈接的庫文件名,libcheck.a為check測試框架的庫文件;)

       使用Automake –a –-foreign來生成Makefile.in文件,--foreign是為了生成幾個外部文件如install.sh等,如果已有這些文件則可以省略這個參數;

       使用Autoconf來生成configure執行腳本;然后執行./configure來生成Makefile文件;

       執行make來生成可執行程序;

      3.2.2 建立測試用例:

      1、以程序文件名加前輟“check_”命名測試單元文件名,比如money.c文件的測試單元文件命名為check_money.c;

      2、加入測試框架頭文件以及要測試的單元頭文件,以check_money為例:

      頭文件:money.h;源文件:money.c;測試單元文件:check_money.c:

      測試文件框架如下:

    #include <stdlib.h>

    #include <check.h>

    #include "money.h"

    /*建立必要的測試變量,Money為money.h中定義的結構struct money*/

    Money *five_dollars;

    /*單元測試初始化函數*/

    void setup (void)

    {

    five_dollars = money_create(5, "USD");

    }

    /*單元測試結束函數*/

    void teardown (void)

    {

    money_free (five_dollars);

    }


    /*單元測試用例,用例名為test_create*/

    /*test functions: money_amout()*/

    START_TEST(test_create)

    {

    /*功能性測試,屬黑盒測試*/

    /*normal test*/

    fail_unless (money_amount(five_dollars) = = 5,

    "Amount not set correctly on creation");

    fail_unless (strcmp(money_currency(five_dollars),"USD") = = 0,

    "Currency not set correctly on creation");

    /*條件及錯誤路徑測試,屬白盒測試*/

    /*extra test*/

    }

    END_TEST


    /*單元測試用例,用例名為test_net_create*/

    START_TEST(test_neg_create)

    {

    Money *m = money_create(-1, "USD");

    fail_unless (m = = NULL, "NULL should be returned on attempt to create with a negative amount");

    }

    END_TEST



    /*單元測試用例,用例名為test_net_create*/

    START_TEST(test_zero_create)

    {

    Money *m = money_create(0, "USD");

    fail_unless (money_amount(m) = = 0,

    "Zero is a valid amount of money");

    }

    END_TEST



    /*單元測試組裝,將所有單元測試組裝到一個“箱子”里面,“箱子”名為Money*/

    Suite *money_suite (void)

    {

    Suite *s = suite_create("Money");



    /*測試用例分組*/

    TCase *tc_core = tcase_create("Core");

    TCase *tc_limits = tcase_create("Limits");



    /*將分組加入“箱子”

    suite_add_tcase (s, tc_core);

    suite_add_tcase (s, tc_limits);



    /*分別將不同用例加入分組*/

    tcase_add_test (tc_core, test_create);

    tcase_add_checked_fixture (tc_core, setup, teardown); /*此用例注冊初始化和結束函數*/

    /*以下用例將不注冊初始化和結束函數*/

    tcase_add_test (tc_limits, test_neg_create);

    tcase_add_test (tc_limits, test_zero_create);

    return s;

    }



    /*執行測試用例*/

    int main (void)

    {

    int nf;

    Suite *s = money_suite();

    SRunner *sr = srunner_create(s);

    srunner_run_all (sr, CK_NORMAL);

    nf = srunner_ntests_failed(sr);

    srunner_free(sr);

    suite_free(s);

    return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;

    }

      3.2.3 制作發行版:

      制作發行版只須配置另外一份Makefile.am,在此文件中的源文件列表加入執行主體,即應用程序包含main函數的文件;也可在制作測試版的Makefile.am中加入發行版的配置,這樣就可以直接生成測試版程序和發行版程序。

    3.3 JAVA標準

    3.3.1測試環境使用JSDK1.3

    3.3.1.1前題:

    使用JUnit3.7版,解壓后,路徑為x:\\junit3.7;

    使用Ant1.3版,解壓后,路徑為x:\\ant1.3;

    配置測試框架使用環境:

    測試框架使用環境可以在build.xml文件中配置,此文件是ant的輸入文件,ant根據其來生成和執行應用程序;(這相當于C/C++的Makefile文件,但比之功能要強大、且配置更為簡單);

    1.x:\\ant1.3\bin目錄下含有ant執行程序的批處理文件,所以要將此目錄加入到系統環境變量path中;

    2.建立項目文件目錄結構;我建議在進行項目開發能有一個完整的目錄結構,如下所示:

    “AntCons”為項目目錄名稱,可以替換為所需要的項目名稱;在項目目錄下有兩個子目錄分別為build和src,這兩個子目錄分別為源文件目錄和發布文件目錄;而src(源文件目錄)又分為main(源文件)和test(測試文件)目錄。而com.myjava則是包名,對應于源java文件中的package;

    3.在項目目錄中建立build.xml文件(未涉及測試的),文件大致結構如下所示:

    定義項目名稱及位置

    首先聲明一些變量,便于使用

    定義目標:編譯;

    在此目標中將建立發布目錄、編譯目標java源文件并且指定class路徑;

    classpath="${java.class.path};${extclasslib}">

    定義目標:運行;

    此目標依賴于編譯目標;

    (build.xml相關標記的說明可以在ant下載包的說明文檔中找到,ant定義了很多方便操作的指令)

    4.編寫代碼文件,我們假設代碼文件位于com.myjava包中,則代碼文件將放置于src/main/com/myjava目錄下;

    5.編寫單元測試文件,依照上面的項目目錄設置,則單元測試文件放置于src/test下;

    3.3.1.2建立測試用例:

    1、以類名加前輟“Test”命名測試單元文件名,比如“Sample”類的類文件名為Sample.java,則測試單元文件命名為TestSample.java;

    2、編寫測試用例類,在測試用例類中引入測試框架包以及要測試的包聲明,以TestSample為例:

    測試文件TestSample.java:

    package test.Sample; //測試包聲明

    import junit.framework.*; //引入測試框架包

    import xxxx; //引入被測試單元包

    //派生測試框架的測試用例類

    public class TestSimple extends TestCase {

    protected int fValue1;

    protected int fValue2;

    public TestSimple(String name) {

    super(name);

    }

    //用例初始化,可作為樁函數

    protected void setUp() {

    fValue1= 2;

    fValue2= 3;

    }

    //用例析構

    protected void tearDown(){

    }

    //組裝測試用例

    public static Test suite() {

    /*

    * the type safe way

    *

    //增加測試用例到“箱子”

    TestSuite suite= new TestSuite();

    suite.addTest(

    new TestSimple("add") {

    protected void runTest() { testAdd(); }

    }

    );

    suite.addTest(

    new TestSimple("testDivideByZero") {

    protected void runTest() { testDivideByZero(); }

    }

    );

    return suite;

    */

    /*

    * the dynamic way

    */

    return new TestSuite(TestSimple.class);

    }

    //用例1:

    public void testAdd() {

    //normal test, 功能測試,屬黑盒測試

    double result= fValue1 + fValue2;

    assertTrue(result == 6);

    //extra test, 條件及錯誤路徑測試,屬白盒測試

    //except test, 異常測試,屬白盒測試

    //other test, see the functions "...",

    //其它測試,比如被測試類的基類方法,在此需要做出說明

    }

    //用例2:

    public void testDivideByZero() {

    //................

    }

    //用例3:

    public void testEquals() {

    //.................

    }

    }

    3. 編寫驅動測試用例類,將各個測試用例組裝到一起進行測試:

    package test.Sample; //測試包聲明

    import junit.framework.*; //引入測試框架包

    import xxxx; //引入被測試單元包

    /**

    * TestSuite that runs all the sample tests

    *

    */

    public class AllTests {

    public static void main (String[] args) {

    junit.textui.TestRunner.run (suite());

    }

    public static Test suite ( ) {

    //建立測試用例的“箱子”

    TestSuite suite= new TestSuite("All Tests");

    suite.addTest(TestSimple.suite());

    //此處增加一些其它單元測試類

    //......

    suite.addTest(junit.tests.AllTests.suite());

    return suite;

    }

    }

    4. 將測試單元的編譯及運行加入到build.xml中;

    在build.xml的project標記加入兩個目標,現在的build.xml如下所示:

    定義項目名稱及位置

    首先聲明一些變量,便于使用

    定義目標:依賴庫檢測;

    定義目標:編譯;

    在此目標中將建立發布目錄、編譯目標java源文件并且指定class路徑;

    classpath="${java.class.path};${extclasslib}">

    定義目標:打包;

    在此目標中將建立分發包目錄、將編譯完成的.class文件打包為jar文件;

    basedir="${builddir}" includes="com/**"/>

    定義目標:編譯測試用例;

    定義目標:運行應用程序;

    此目標依賴于編譯目標;

    定義目標:運行測試用例;

    在此目標中將運行測試用例,運行在窗口中進行還是在控制臺進行取決于所用classname,"junit.textui.TestRunner"表示在控制臺進行,如果改為"junit.ui.TestRunner"則可以在窗口中運行

    taskname="junit" failonerror="true">


    5. 最后,在項目所在目錄執行Ant target_name,比如:運行測試用例可以使用Ant runtests;

    3.3.2 使用Junit測試EJB

    3.3.2.1安裝JUnit和JunitEE

    你需要將junit.jar和junitee.jar加入到J2EE應用程序的CLASSPATH中。一般地,將jar文件拷貝到服務器的根目錄下的lib目錄中就可以了。注意:該目錄下的文件一般不能被動態加入,所以你需要重新啟動應用服務器。

    3.3.2.2準備一個EJB例子

    你可以在JunitEE安裝目錄的example子目錄下找到一個作為示例的EJB。你要先組織該示例,保證它是可以工作的。否則,注意發生了什么事情。你要編輯build.xml文件按照你計算機的具體情況更新文件中的路徑。然后在build文件所在的目錄下運行“ant”。
    《something》

    運行該例子的結果是得到名為junitee-example.ear的文件。該文件在名為out的子目錄中。它包含一個簡單的無狀態EJB,一個使用了EJB的應用程序和測試web應用程序。這是一個標準的J2EE企業級的文檔,可以安裝在任何的應用服務器上。

    如果你想手工的寫出所有的部分,就刪除example目錄下的components/test-war子目錄,本文下面的部分就是說明如何構建測試。

    3.3.2.3創建目錄結構

    要創建一個Web應用程序測試,首先你要創建目錄結構。創建下面的子目錄:
    example/javasrc/org/infohazard/test/
    example/components/test-war/
    example/components/test-war/WEB-INF/

    本示例將測試用例放置在org.infohazard.test包中。如果你想測試包內的私有方法,則要將測試用例和要測試的class文件放置在同一個包中。由于絕大多數的測試發生在public接口層,所以你要考慮是不是要這樣做。

    3.3.2.4編寫測試用例

    測試用例是標準的JUnit測試用例。對于fixture,你可以使用缺省的JNDI InitialContext來得到EJB的索引,如下:

    protected void setUp() throws Exception
    {
    Context jndiContext = new InitialContext();
    Object einRef = jndiContext.lookup("java:comp/env/ejb/EinsteinEJB");
    EinsteinHome home = (EinsteinHome)PortableRemoteObject.narrow(einRef, EinsteinHome.class);
    this.ein = home.create();
    }

    測試方法類似于:

    public void testSimpleAddition() throws RemoteException
    {
    String result = this.ein.addTwoNumbers("7", "10");
    assert(result.equals("17"));
    }

    這些代碼屬于example/javasrc/org/infoazard/test/EinsteinTest.java

    3.3.2.5使用 servlet來運行測試用例

    下面是一個包括在junit.htmlui包中的servlet,但是你不可以直接使用它。你必須在你的web應用程序的WEB-INF/classes/下創建一個servlet,這個servlet來源于junit.htmlui.TestServletBase并且增加了下面的細節:

    protected ClassLoader getDynamicClassLoader()
    {
    return this.getClass().getClassLoader();
    }

    使用這個servlet,我們使用動態的類載入器欺騙應用服務器,這樣不必使用缺省的類載入。如果我們不這樣做,每次改變的測試類文件都要重新啟動web應用服務器。

    如果你的應用程序服務器不能動態地重新載入修改過的class文件,這一步對你來說是沒有幫助的。你不得不重新啟動服務器,因為TestServletBase被聲明為abstract類型。

    3.3.2.6創建UI表格

    <p>
    You may type in the name of a test suite:
    <br/>
    <form action="TestServlet" method="get" name="youTypeItForm">
    <input type="text" name="suite" size=60 />
    <input type="submit" value="Run" />
    </form>
    </p>
    <hr/>
    <p>
    You may pick one or more of the following test suites:
    <br/>
    <form action="TestServlet" method="get" name="youPickItForm">
    <select name="suite" size="2" multiple>
    <option value="org.infohazard.test.EinsteinTest">
    org.infohazard.test.EinsteinTest
    </option>
    <option value="some.other.Test">
    some.other.Test
    </option>
    </select>
    <input type="submit" value="Run" />
    </form>
    </p>

    將此保存為example/components/test-war/index.html文件。

    3.3.2.7 創建web.xml配置描述器

    Web應用程序必須有一個配置描述器,它提供了ejb-ref映射,使得"java:comp/env/ejb/EinsteinEJB" JNDI lookup生效,and so that the TestServlet gets mapped to some sort of URI.下面是web.xml的示例:

    <?xml version="1.0"?>
    <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
    <web-app>
    <display-name> Einstein Unit Tester Web Application </display-name>
    <servlet>
    <servlet-name>JUnitEETestServlet</servlet-name>
    <description>JUnitEE test framework</description>
    <servlet-class>org.infohazard.servlet.TestServlet</servlet-class>
    </servlet>
    <ejb-ref>
    <ejb-ref-name>ejb/EinsteinEJB</ejb-ref-name>
    <ejb-ref-type>Session</ejb-ref-type>
    <home>org.infohazard.ejb.einstein.EinsteinHome</home>
    <remote>org.infohazard.ejb.einstein.Einstein</remote>
    </ejb-ref>

    <servlet-mapping>
    <servlet-name>JUnitEETestServlet</servlet-name>
    <url-pattern>/TestServlet</url-pattern>
    </servlet-mapping>
    </web-app>

    保存成:example/components/test-war/WEB-INF/web.xml。

    3.4 單元測試完畢后,程序員將測試用例交與項目經理,由項目經理進行單元測試的檢查,完成單元測試報告,對測試的情況進行總結說明。

    注意:以上所述僅是測試J2EE的一種方式而已,我們還可以結合HttpUnit和Jakarta Cataus來進行J2EE項目的單元測試。這些完全借助于工具的方式還是有一定的缺陷,所以在去年的時候我根據XP中的Mock Object理論的一些指導,在HttpUnit的基礎上編寫了一套完全脫離J2EE運行環境(比如Weblogic等)的單元測試套件,以及壓力測試和功能測試套件,在這一組工具的支持下才算作好了J2EE項目的單元測試。

    延伸閱讀

    文章來源于領測軟件測試網 http://www.kjueaiud.com/

    TAG: 單元測試


    關于領測軟件測試網 | 領測軟件測試網合作伙伴 | 廣告服務 | 投稿指南 | 聯系我們 | 網站地圖 | 友情鏈接
    版權所有(C) 2003-2010 TestAge(領測軟件測試網)|領測國際科技(北京)有限公司|軟件測試工程師培訓網 All Rights Reserved
    北京市海淀區中關村南大街9號北京理工科技大廈1402室 京ICP備2023014753號-2
    技術支持和業務聯系:info@testage.com.cn 電話:010-51297073

    軟件測試 | 領測國際ISTQBISTQB官網TMMiTMMi認證國際軟件測試工程師認證領測軟件測試網

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>