1. 程式人生 > >(三)在TestNG中傳遞引數給方法使用

(三)在TestNG中傳遞引數給方法使用

TestNG允許我們在Test Method 以及 @Before/After類註解 、 @Factory類註解註解的方法中傳入引數

引數傳遞的方式有兩種,一種是藉助xml檔案配置,一種是以編碼的方式傳遞引數。

一、藉助xml檔案配置:

1.在方法上使用@Parameters({"paraname"})註解,然後在套件xml檔案中宣告變數即可使用。方法有多少個引數,就需要在@Parameters內宣告多少個變數,兩者引數順序對應。另外Test提供了@Optional註解,可以為引數提供預設值,如果在xml檔案沒有找到這個變數,則會使用@Optional的預設值。

示例:新建一個TestNG類和對應的xml配置檔案。

import org.testng.annotations.Optional;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;

public class ParameterExample {
	@Parameters({"xxx","yyy","varNotFound"})
	@Test
	public void parameterExample(String p1, String p2, @Optional("this is default value") String p3 ){
		System.out.println(p1+"  "+p2);
		System.out.println(p3);
	}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="testSuite">
	<parameter name="yyy"  value="hello yyy"/>
	<parameter name="xxx"  value="hello xxx"/>
	<test name="test1">
		<classes>
			<class name ="com.testng.ParameterExample" />
		</classes>
	</test>
</suite>

上面的例子,聲明瞭三個變數,引數名依次為xxx, yyy, varNotFound。在xml檔案中分別定義了xxx和yyy變數,varNotFound沒有在xml檔案中定義,因此會使用@Optional註解的預設值。上面程式碼的輸出結果如下:


我們要注意parameter引數在xml檔案中宣告的位置,因為這些引數也是有作用域的,這些引數的宣告既可以放在套件suite下也可以放在用例test下。對於在suite和test中都聲明瞭的同名變數,在Test內的變數會覆蓋掉Suite的變數。這個很好理解,類比java,區域性變數在其作用域內也會覆蓋掉全域性變數。比如下面的程式碼,在xml檔案中,同時在suite域和test域聲明瞭變數sameNameVar,當我們執行這個Test的時候,會使用這個Test內部的sameNameVar變數而不是來自Suite的sameNameVar。

package com.testng;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;

public class TestParaScope {
	@Parameters({"sameNameVar"})
	@Test
	public void parameterExample(String p){
		System.out.println(p);
	}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="testSuite">
	<parameter name="sameNameVar"  value="定義在Suite的變數被使用了"/>

	<test name="test1">
		<parameter name="sameNameVar"  value="定義在Test的變數被使用了"/>
		<classes>
			<class name ="com.testng.TestParaScope" />
		</classes>
	</test>
</suite>

執行結果;


二、藉助編碼方式:

在xml檔案中配置引數的方式,比較適合傳遞一些簡單引數。藉助編碼方式,我們可以往Test Method裡傳遞複雜的物件。編碼傳參,需要使用@DataProvider註解,被@DataProvider註解的方法,只能返回一個Object二維陣列或一個Iterator<Object[]>來提供複雜的引數物件。我們先講返回Object[][]二維陣列的情況。Object[][]這個二維陣列的每一個一維陣列代表一個物件。這個一維陣列中的元素型別,個數必須和使用這個provider的函式的引數匹配。使用這個Provider的Method會遍歷Provider傳遞過來的每一個物件,每個物件都執行一次方法體內的程式碼。


我們結合程式碼來理解

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

public class TestDataProvider {
	@DataProvider(name = "myDataProvider")
	public Object[][] myDataProvider(){
		/*返回一個二維陣列*/
		return new Object[][]{
			/*二維陣列下的每一個一維陣列*/
			{ "Apple",  new Integer(20)},
			{ "Banana",  new Integer(11)}
		};
	}

	@Test(dataProvider = "myDataProvider")
	public void testDataProvider(String fruitName, Integer fruitNum){
		System.out.println("我從myDataProvider倉庫拿到了" + fruitNum + "個" + fruitName);
	}
}

這段程式碼中的DataProvider提供了一個二維陣列,這個二維陣列下的每一個一維陣列,都是一個水果物件,這個水果物件的屬性有兩個,分別是水果名稱和水果價格,水果名稱是String型別,水果價格是Integer型別。使用了這個DataProvider的Method的引數列表有兩個引數,對應了水果物件的兩個屬性,這兩個引數型別也和水果的兩個屬性的引數型別相對應。TestMethod對DataProvider傳遞過來的每個物件,都會執行依次方法體內的程式碼,因此我們會得到兩行輸出。


在擁有大量有規律的測試資料的時候,我們可不想以敲出一個個一維陣列初始化為二維陣列的形式來初始化測試資料。這時候我們可以使用返回型別為Iterator<Object[]>的DataProvider,有同學可能就會困惑了,如果DataProvider返回Iterator<Object[]>那Test Method要怎麼寫才能收下這些資料呢Iterator<Object[]>Object[][]的區別就在於,Iterator充當了二維陣列的第二維,實際上就是遍歷的方式變了,核心的東西還是它裡面的一維陣列,所以我們前面說的一維陣列的元素個數,元素型別必須和使用的Test Method的引數列表一致的原則還是適用的。所以不管返回型別是啥,Test Method該咋寫就咋寫。下全面我給出了兩個返回Iterator<Object[]>的例子,可以看下TestMethod的引數列表是如何寫的。

package com.testng;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class TestDataProvider {
	/*水果物件類*/
	class Fruit{
		Fruit(String f, Integer n){
			fruitName = f;
			fruitNum = n;
		}
		private String fruitName;
		private int fruitNum;
		
		public String getFruitName() {
			return fruitName;
		}
		public void setFruitName(String fruitName) {
			this.fruitName = fruitName;
		}
		public int getFruitNum() {
			return fruitNum;
		}
		public void setFruitNum(int fruitNum) {
			this.fruitNum = fruitNum;
		}
	}
	
	@DataProvider(name = "iteratorDataProvider")
	public Iterator<Object[]> iteratorDataProvider(){
		List<Object[]> objList = new ArrayList<Object[]>();
		for(int i = 1; i < 5; i++){
			/*我這裡一維陣列元素個數是2,第一個元素是String,第二個元素是Integer,所以TestMethod的引數有兩個,一個是String,一個是Integer*/
			objList.add(new Object[]{"第" + i  + "名得分", new Integer(i) });
		}
		return objList.iterator();
	}
	
	@Test(dataProvider = "iteratorDataProvider")
	public void testDataProvider(String str, Integer i){
		System.out.println(str+i);
	}
	
	@DataProvider(name = "myDataProvider")
	public Iterator<Object[]> myDataProvider(){
		List<Fruit> fList = new ArrayList<Fruit>();
		fList.add(new Fruit("Apple", new Integer(123)));
		fList.add(new Fruit("Banana", new Integer(456)));
		List<Object[]> fArrList = new ArrayList<Object[]>();
        for (Object f : fList) {
        	/**
        	 * 注意我這裡是new一個元素為Fruit的陣列,前面我們說了,一維陣列的元素型別,元素個數要和使用的函式引數列表一致,
        	 * 那麼下面的TestMethod的引數列表就應該只有一個元素,且元素型別為Fruit
        	 * */
        	fArrList.add(new Object[] { f });
        }
		return fArrList.iterator();
	}
	
	@Test(dataProvider = "myDataProvider")
	public void testDataProviderObject(Fruit f){
		System.out.println("我從myDataProvider倉庫拿到了" + f.getFruitName() + "個" + f.getFruitNum());
	}

}
輸出:

還有一點提一下,如果你希望別的類宣告DataProvider方法,然後在另一個TestNG類內使用它,那麼這個DataProvider方法必須被宣告為靜態方法,且在使用的時候,需要宣告它所屬的類。

public class StaticProvider {
  @DataProvider(name = "create")
  public static Object[][] createData() {
    return new Object[][] {
      new Object[] { new Integer(42) }
    };
  }
}
 
public class MyTest {
  @Test(dataProvider = "create", dataProviderClass = StaticProvider.class)
  public void test(Integer n) {
    // ...
  }
}

那麼,TestNG中給方法傳遞引數的方式介紹就到此為止辣。附上TestNG官官方文件,你想查的都在這裡: