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

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

  • <strong id="5koa6"></strong>
  • 測試分類技術與Testing

    發表于:2007-11-12來源:作者:點擊數: 標簽:testng
    TestNG是一種基于注釋的 測試框架 ,通過添加諸如靈活的裝置、測試分類、參數測試和依賴方法等特性來克服JUnit的一些不足之處。此外,TestNG運行于 Java 5.0(通過注釋)和Java 1.4(通過JavaDoc樣式的注釋)之上。由于TestNG可以輕松地將開發人員測試分類成
     TestNG是一種基于注釋的測試框架,通過添加諸如靈活的裝置、測試分類、參數測試和依賴方法等特性來克服JUnit的一些不足之處。此外,TestNG運行于Java 5.0(通過注釋)和Java 1.4(通過JavaDoc樣式的注釋)之上。由于TestNG可以輕松地將開發人員測試分類成單元、組件和系統組,因此能夠使構建時間保持在可管理的范圍內。通過使用group注釋和多重Ant任務,測試組可以不同的頻率運行于一臺工作站之上或持續集成環境中。

      本文分析了測試分類的概念,演示了如何將TestNG的group注釋與靈活的測試裝置具相結合,通過特定的Ant目標促進以不同頻率運行的測試。本文假設您了解TestNG。

    TestNG組的研究

      TestNG支持一種直觀的機制,用于分組測試類和相關測試方法。在最基本的層面上,TestNG的分組特性是通過test注釋的groups參數啟用的,它可附加到類或者單個方法。從其名稱即可看出,一個類或單個方法可屬于1至n組。

      例如,下面的類包含兩個公共方法,缺省標為測試并進一步分類為屬于one組:

    /**
    * @testng.test groups="one"
    */
    public class SimpleGroupedTest {
    private String fixture;
    /**
    * @testng.before-class = "true"
    */
    private void init(){
    this.fixture = "Hello World";
    }

    public void verifyEquality(){
    Assert.assertEquals("Hello World", this.fixture);
    }

    public void verifySame(){
    String value = this.fixture;
    Assert.assertSame(this.fixture, value);
    }
    }

      相反,下一個類定義了兩個測試方法。然而,一個方法卻屬于兩個不同的組——one和two。相應地,任何相關裝置邏輯都必須與其所需的一個組關聯。本例中,在組one或組two執行之前,必須首先將init()方法配置為運行。

    public class SimpleGroupedTwoTest {
    private String fixture;
    /**
    * @testng.before-class = "true"
    * groups = "one, two"
    */
    private void init(){
    this.fixture = "Hello World";
    }
    /**
    * @testng.test groups="one, two"
    */
    public void verifyEqualityAgain(){
    Assert.assertEquals(this.fixture, "Hello World");
    }
    /**
    * @testng.test groups="two"
    */
    public void verifySameAgain(){
    String value = this.fixture;
    Assert.assertSame(value, this.fixture);
    }
    }

      TestNG支持以多種方式運行所需組,從通過TestNG Eclipse插件指定這些組一直到在TestNG Ant任務中列舉它們。

    測試分類簡介

      要驗證正在工作的軟件,最簡單的方法之一就是執行一次構建(即編譯源代碼并執行測試);因此,長時間運行的構建是降低開發人員生產力的一項因素,這一點也不令人吃驚。不得不等待那超長的構建過程完成,幾乎沒有什么比這更惱人的了??膳c之相提并論的就是編碼過程中遇到意外的藍屏和重啟,但我們至少能夠很容易地對時間較長的構建做點什么。

      長時間構建的原因幾乎總是測試執行這個步驟(除非是有數百萬的.java 文件)。此外,如果存在大量的設置步驟,例如配置數據庫或是部署一個 EAR 文件,執行一個測試套件的總時間傾向于變長。所以,精心設計一個測試分類策略并按照規定的時間間隔運行分類有利于獲得可管理的構建持續時間。

      然而,分類測試要求我們定義具體的分類,即細化單元測試。單元測試就像一張三層餅的一片,另兩片則是組件測試和系統測試。下一節分析了開發人員通常會編寫的不同類型的測試,諸如單元測試、組件測試和系統測試。隨后,它們將在TestNG中執行,并集成到一個Ant 構建腳本里。

    單元測試定義
      單元測試驗證獨立對象的行為;然而,由于類的耦合,單元測試也能驗證相關對象的行為。例如,下面的單元測試驗證了對象身份,它是在TestNG中實現的,只關注一個類型:PartOfSpeechEnum。

    /**
    * @testng.test
    */
    public class PartOfSpeechEnumTest {

    public void verifyNotEquals() throws Exception{
    assert PartOfSpeechEnum.ADJECTIVE !=
    PartOfSpeechEnum.NOUN: "NOUN == ADJECTIVE?";
    }

    public void verifyEquals() throws Exception{
    assert PartOfSpeechEnum.ADJECTIVE ==
    PartOfSpeechEnum.ADJECTIVE "ADJECTIVE != ADJECTIVE";
    }
    }

      有些時候,一個單元測試會驗證多個對象的行為。然而,這些對象很少有其他的外部依賴項。例如,下面的測試驗證了兩個對象:Dependency和DependencyFinder。

    //imports removed...

    public class DependencyFinderTest {
    private DependencyFinder finder;
    /**
    * @testng.test
    */
    public void verifyFindDependencies() throws Exception{
    String targetClss = "test.com.sedona.frmwrk.dep.Finder";
    Filter[] filtr = new Filter[] {
    new RegexPackageFilter("java|org")};
    Dependency[] deps =
    finder.findDependencies(targetClss, filtr);
    Assert.assertNotNull(deps, "deps was null");
    Assert.assertEquals(deps.length, 5, "should be 5 large");
    }
    /**
    * @testng.before-class = "true"
    */
    protected void init() throws Exception {
    this.finder = new DependencyFinder();
    }
    }
      要牢記的一個要點就是:單元測試不依靠外部依賴項,如數據庫。數據庫會增加設置和運行測試的時間。單元測試沒有配置成本(就時間來度量),運行它的資源消耗可忽略不計。

      單元測試運行很快,所以只要運行了一次構建,就應該運行單元測試,包括在持續集成環境中也是如此。在持續集成環境中,如果源儲存庫(如CVS)發生變更,通常就要運行構建。

    組件測試

      組件測試有幾個別名,如子系統測試或集成測試。不管用哪個術語,這樣的測試驗證了應用程序的若干部分,甚至還可能需要一個完全安裝的系統或一組更有限的外部依賴項,如數據庫、文件系統、或網絡端點。實質上,這些測試驗證了不同組件交互以產生預期組合行為的過程。

      典型的組件測試需要一個種子數據庫(seeded database);此外,測試本身可能要跨架構邊界來驗證行為。由于組件測試要處理大量的代碼,所以實現了更廣泛的代碼覆蓋范圍;但運行此類測試要比運行單元測試占用更長時間。

      因為組件測試有相關成本——依賴項必須就位并被配置好,所以不該在每次執行構建時運行,而應以規定的時間間隔運行。記住,這些測試本身可能只需幾秒鐘,但更多的組件測試被添加到套件中時,整個測試時間就增加了,而且往往增加的非???。

      例如,下面的組件測試用DbUnit 播種一個底層數據庫。這一測試用例中,設置本身所用的時間比大多數單元測試的運行時間都要長。

    //imports removed...

    public class WordDAOImplTest {
    private WordDAO dao = null;
    /**
    * @testng.before-method = "true"
    */
    private void setUp() throws Exception {
    final ApplicationContext context =
    new ClassPathXmlApplicationContext(
    "spring-config.xml");
    this.dao = (WordDAO) context.getBean("wordDAO");
    }
    /**
    * @testng.before-class = "true"
    */
    public void oneTimeSetUp() throws Exception{
    final IDatabaseConnection conn =
    this.getConnection();
    final IDataSet data = this.getDataSet();
    try{
    DatabaseOperation.CLEAN_INSERT.execute(conn, data);
    }finally{
    conn.close();
    }
    }
    /**
    * @testng.test
    */
    public void createWord() {
    final IWord word = new Word();
    word.setSpelling("pabulum");
    word.setPartOfSpeech(
    PartOfSpeechEnum.NOUN.getPartOfSpeech());
    final IDefinition defOne = new Definition();
    defOne.setDefinition("food");
    defOne.setWord(word);
    final Set defs = new HashSet();
    defs.add(defOne);
    word.setDefinitions(defs);
    try{
    this.dao.createWord(word);
    }catch(CreateException e){
    Assert.fail("CreateException was thrown");
    }
    }

    private IDataSet getDataSet()
    throws IOException, DataSetException {
    return new FlatXmlDataSet(
    new File("test/conf/words-seed.xml"));
    }

    private IDatabaseConnection getConnection()
    throws ClassNotFoundException, SQLException {
    final Class driverClass =
    Class.forName("org.gjt.mm.mysql.Driver");
    final Connection jdbcConnection = DriverManager.
    getConnection("jdbc:mysql://localhost/words",
    "words", "words");
    return new DatabaseConnection(jdbcConnection);
    }
    }

      但是,組件測試不總是依靠數據庫。例如依靠文件系統創建一個耦合,這會增加配置的復雜性,在某些情況下,也會增加所需時間。舉個例子,下面的組件測試使用XMLUnit 驗證所生成的XML。注意這個測試依靠文件系統路徑來比較兩個XML文檔。

    //imports removed...

    public class BatchDepXMLReportValidationTest {
    /**
    * @testng.before-class = "true"
    */
    protected void configure() throws Exception {
    XMLUnit.setControlParser(
    "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
    XMLUnit.setTestParser(
    "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
    XMLUnit.setSAXParserFactory(
    "org.apache.xerces.jaxp.SAXParserFactoryImpl");
    XMLUnit.setIgnoreWhitespace(true);
    }

    private Filter[] getFilters(){
    return new Filter[] {
    new RegexPackageFilter("java|org"),
    new SimplePackageFilter("junit.")
    };
    }

    private Dependency[] getDependencies(){
    return new Dependency[] {
    new Dependency("com.vanward.resource.XMLizable"),
    new Dependency("com.vanward.xml.Element")
    };
    }
    /**
    * @testng.test
    */
    public void assertToXML() throws Exception{
    BatchDependencyXMLReport report =
    new BatchDependencyXMLReport(
    new Date(9000000), this.getFilters());

    report.addTargetAndDependencies(
    "com.vanward.test.MyTest", this.getDependencies());
    report.addTargetAndDependencies(
    "com.xom.xml.Test", this.getDependencies());

    Diff diff = new Diff(new FileReader(
    new File("./test/conf/report-control.xml")),
    new StringReader(report.toXML()));

    Assert.assertTrue(
    diff.identical(),"XML was not identical");
    }
    }

      雖然不應在每次運行構建時執行組件測試,但在將代碼提交到儲存庫之前運行組件測試卻是一個好主意。在持續集成環境中,時常運行它很可能是個好主意,比如每小時一次。

    系統測試

      系統測試處理一個完整的軟件應用程序,驗證外部接口,如Web頁面、Web 服務端點、GUI、按照設計端到端地完成工作。因為系統測試處理的是整個系統,所以往往在開發的后期創建。除增加了設置和配置時間之外,系統測試還傾向于具有更長的執行時間。

      例如,以下測試使用 jWebUnit 測試一個Web站點的登陸功能。請注意,這個測試中做了許多假設,如可用URL、實際上擁有有效賬戶的“tst”用戶、未提及交易歷史記錄等。這些隱含的依賴項通常需要在測試運行前完成一個配置步驟。

    public class LoginTest {
    private WebTester tester;
    /**
    * @testng.before-class = "true"
    */
    protected void init() throws Exception {
    this.tester = new WebTester();
    this.tester.getTestContext().
    setBaseUrl("http://stocktrader.com");
    }
    /**
    * @testng.test
    */
    public void verifyLogIn() {
    this.tester.beginAt("/");
    this.tester.setFormElement("user", "tst");
    this.tester.setFormElement("psswd", "t@t");
    this.tester.submit();
    this.tester.assertTextPresent("Logged in as tst");
    }
    /**
    * @testng.test dependsOnMethods = "verifyLogIn"
    */
    public void verifyAclearcase/" target="_blank" >ccountInfo() {
    this.tester.clickLinkWithText("History", 0);
    this.tester.assertTextPresent(".00, sold");
    }
    }

      開發人員應當以需求為基礎,在一個持續集成環境中本地運行這些測試。每晚執行測試是個不錯的策略(如果測試能夠實現自動運行)。更頻繁地運行測試可能消耗大量系統資源,特別是在較大的環境中。但有了合理的硬件規劃和更加完善的自動化,團隊就能更頻繁地運行這些測試。

    實現TestNG分類

      將TestNG測試分成三類就像使用上面所講的group注釋一樣簡單。通常不會有一個具有跨不同測試粒度的方法的測試類,所以在類的級別上,可以有效地應用標記。

      例如,下面的類被標記為屬于unit測試組。請注意,HierarchyBuilderTest是怎樣依靠HierarchyBuilder類型來驗證Hierarchy類的行為的。由于這一關系結束于不依賴文件系統或數據庫的HierarchyBuilder,因此實際上可以把它看作單元測試:

    import org.testng.Assert;

    /**
    * @testng.test groups="unit"
    */
    public class HierarchyBuilderTest {
    private Hierarchy hier;
    /**
    * @testng.before-class = "true" groups="unit"
    */
    private void init() throws Exception{
    this.hier =
    HierarchyBuilder.buildHierarchy(Vector.class);
    }

    public void validateIsntNull() throws Exception{
    Assert.assertNotNull(this.hier,
    "should be something!");
    }
    /**
    * @testng.test dependsOnMethods="validateIsntNull"
    */
    public void validateValues() throws Exception{
    Assert.assertEquals(
    this.hier.getHierarchyClassNames().length,
    2, "should be 2");
    }
    }

      類似地,系統測試中單獨的方法可以用system組標識來標記,示范如下:

    public class LoginTest {
    private WebTester tester;
    /**
    * @testng.before-class = "true" groups="system"
    */
    protected void init() throws Exception {
    this.tester = new WebTester();
    this.tester.getTestContext().
    setBaseUrl("http://acme.com:8080/ppo/");
    }
    /**
    * @testng.test groups="system"
    */
    public void verifyView() {
    this.tester.beginAt("/");
    this.tester.setFormElement("isbn", "900930390");
    this.tester.submit();
    this.tester.assertTextPresent("Book in stock");
    }
    }

    運行分類測試

      將代碼簽入內容管理系統之前,通過構建或像IDE那樣的環境進行本地測試是極為重要的。通過TestNG Eclipse插件運行分類測試非常簡單。如圖1所示,通過在TestNG Create, manage, and run configurations 對話框中選擇組選項,可用組的列表將出現,它帶有復選框,這使選擇變得更輕松。選好所需的一個或多個組以后,單擊Run按鈕,然后就看著綠色進度條一直向前!

      通過構建,運行分類TestNG 測試將轉變成為各組定義恰當的 Ant 目標。例如,為了運行屬于組件組的所有測試,用指定的component組定義TestNG Ant 任務。

    <target name="testng-component"
    depends="testng-init">
    <mkdir dir="$"/>

    <testng groups="component"
    outputDir="$"
    sourceDir="$"
    classpath="$; $">
    <classfileset dir="$">
    <include name="**/*Test.java"/>
    </classfileset>
    <classpath>
    <path refid="build.classpath"/>
    </classpath>
    </testng>

      因此,采用這一策略,至少可以創建4個目標。其中3個分別對應單元、組件和系統測試,最后一個目標則能運行所有這3種測試。

    結束語

      TestNG使測試分類變得相當容易,這很可能是TestNG的最激動人心的優點之一。此外,TestNG的group注釋還有助于把測試放到其他分類中,如成批測試、驗收測試,甚至是性能測試。事實上,這一特性似乎已對最新版本的JUnit產生了影響,JUnit也在規劃支持測試組!

    原文轉自:http://www.kjueaiud.com

    老湿亚洲永久精品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>