TestNG參數化有何特別之處

大家好,我是剛哥。

TestNG作爲Java技術棧一個極其強大的測試框架,想必在參數化這塊也有一定的特別之處,本文就來根據官方文檔,對TestNG參數化進行一探究竟。

TestNG參數化有兩種方式,第一種是從testng.xml讀取數據,第二種是通過代碼讀取數據。

從testng.xml讀取數據

直接看示例:

@Parameters({ "first-name" })
@Test
public void testSingleString(String firstName) {
  System.out.println("Invoked testString " + firstName);
  assert "Cedric".equals(firstName);
}

<suite name="My suite">
  <parameter name="first-name"  value="Cedric"/>
  <test name="Simple example">
  <-- ... -->

  • @Parameters指定參數化名字。

  • 測試方法入參與參數化名字一一對應。

  • testng.xml中<parameter>定義參數化的值。

    在testng.xml中,<parameter>既可以定義在<suite>中也可以定義在<test>中,如果有同名的,會以<test>的覆蓋<suite>

@Parameters既可以作用到@Test,也可以作用到 @Before/After@Factory,比如:

@Parameters({ "datasource", "jdbcDriver" })
@BeforeMethod
public void beforeTest(String ds, String driver) {
  m_dataSource = ...;                              // look up the value of datasource
  m_jdbcDriver = driver;
}

也可以作用到測試類的構造方法中,但是隻能最多一個構造方法,這樣就能在初始化類的時候,進行參數化賦值,便於測試方法使用

@Optional用於標識參數是否可選,比如:

@Parameters("db")
@Test
public void testNonExistentParameter(@Optional("mysql") String db) { ... }

  • 如果db這個參數取不到名字,那麼就會取mysql的值。

通過代碼讀取數據

第一種參數化方式其實比較雞肋,第二種方式纔是TestNG參數化的靈魂,用到了@DataProvider,它會返回一個二維數組:

import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class DPTest {
    @DataProvider(name = "test1")
    public Object[][] createData1() {
        return new Object[][] {
                { "Cedric", 36},
                { "Anne", 37},
        };
    }

    @Test(dataProvider = "test1")
    public void verifyData1(String n1, Integer n2) {
        System.out.println(n1 + " " + n2);
    }
}

  • @DataProvider用於生產數據,name是唯一標識。
  • 在@Test中通過dataProvider屬性指定name。
  • 測試方法的入參跟數組中元素一一對應。

默認@DataProvider和@Test是在同一個類中,如果想放在不同的類,那麼需要定義爲靜態方法(或者無參數構造方法的類),比如:

import org.testng.annotations.DataProvider;

public class StaticProvider {
    @DataProvider(name = "create")
    public static Object[][] createData() {
        return new Object[][] {
                new Object[] {42}
        };
    }
}

import org.testng.annotations.Test;

public class DiffClazzTest {
    @Test(dataProvider = "create", dataProviderClass = StaticProvider.class)
    public void test(Integer n) {
        System.out.println(n);
    }
}

  • createData()爲static。
  • 需要額外通過@Test的dataProviderClass屬性指定@DataProvider所在的類。

@DataProvider的返回值(參數類型)除了已經提到的Object[][],還可以是Iterator<Object[]>,它不會一次性生成所有數據,而是每調用一次生成一次,節約內存,比如:

import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import java.util.Arrays;
import java.util.Iterator;

public class IterTest {
    @DataProvider(name = "test1")
    public Iterator<Object[]> createData1() {
        Object[][] myObjects = new Object[][]{
                {"Cedric", 36},
                {"Anne", 37},
        };
        return Arrays.asList(myObjects).iterator();
    }

    @Test(dataProvider = "test1")
    public void verifyData1(String n1, Integer n2) {
        System.out.println(n1 + " " + n2);
    }
}

看到這裏,對@DataProvider已經有了足夠的認識,它支持兩種參數類型

  • Object[][]
  • Iterator<Object[]>

假如測試方法只有一個入參,是不是隻能用二維來實現:

import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import java.util.Arrays;
import java.util.Iterator;

public class IterTest {
    @DataProvider(name = "test1")
    public Iterator<Object[]> createData1() {
        Object[][] myObjects = new Object[][]{
                {"x"},
                {"y"}
        };
        return Arrays.asList(myObjects).iterator();
    }

    @Test(dataProvider = "test1")
    public void verifyData1(String n) {
        System.out.println(n);
    }
}

其實不是,@DataProvider支持一維數組:

import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import java.util.Arrays;
import java.util.Iterator;

public class IterTest {
    @DataProvider(name = "test1")
    public Object[] createData1() {
        Object[] myObjects = new Object[]{
                "x",
                "y"
        };
        return myObjects;
    }

    @Test(dataProvider = "test1")
    public void verifyData1(String n) {
        System.out.println(n);
    }
}

以及一維數組的迭代器:

import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import java.util.Arrays;
import java.util.Iterator;

public class IterTest {
    @DataProvider(name = "test1")
    public Iterator<Object> createData1() {
        Object[] myObjects = new Object[]{
                "x",
                "y"
        };
        return Arrays.asList(myObjects).iterator();
    }

    @Test(dataProvider = "test1")
    public void verifyData1(String n) {
        System.out.println(n);
    }
}

最精彩的來了,@DataProvider支持反射,也就是反向獲取測試方法的信息:

@DataProvider(name = "dp")
public Object[][] createData(Method m) {
  System.out.println(m.getName());  // print test method name
  return new Object[][] { new Object[] { "Cedric" }};
}
 
@Test(dataProvider = "dp")
public void test1(String s) {
}
 
@Test(dataProvider = "dp")
public void test2(String s) {
}

  • createData的入參是java.lang.reflect.Method,這樣就能獲取到測試方法的信息,比如這裏的getName()會依次拿到test1、test2。

@DataProvider還支持併發:

@DataProvider(parallel = true)
// ...

默認是10個線程,可以在testng.xml中修改:

<suite name="Suite1" data-provider-thread-count="20" >
...

一個xml共享一個線程池,如果要用多個線程池,那麼需要創建多個testng.xml。

錦上添花的是,TestNG的參數化會打印在測試報告中:

img

參考資料:

https://testng.org/doc/documentation-main.html 5.6 - Parameters

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章