2013-03-05 135 views
21

我正在開發一個項目,我需要以編程方式調用TestNG(使用數據提供程序)。事情沒有問題,只是在報告中,我們得到了@Test方法的名稱,這是處理大量情況的通用方法。我們想要的是在報告中獲得一個有意義的名字。TestNG報告中的自定義測試方法名稱

我在這方面正在研究並找到3種方法,但不幸的是,對我來說都是失敗的。

1)實施ITEST

我發現這個herehere

我設置我,只要我進入@Test方法(對於所有3種方式,我試圖想要的名字,這是我設置名稱的方式)。該名稱從getTestName()返回。我觀察到的是getTestName()在我的@Test之前和之後被調用。最初,它返回null(用於處理NullPointerException,我返回「」而不是null),然後它返回正確的值。但我沒有看到這個越來越反映在報告中

編輯:也嘗試設置從@ BeforeMethod名稱由artdanil的建議

2和3

兩者都是基於給定的解決方案在second link above

通過XmlSuite覆蓋的setName,我越來越

Exception in thread "main" java.lang.AssertionError: l should not be null 
     at org.testng.ClassMethodMap.removeAndCheckIfLast(ClassMethodMap.java:58) 
     at org.testng.internal.TestMethodWorker.invokeAfterClassMethods(TestMethodWorker.java:208) 
     at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:114) 
     at org.testng.TestRunner.privateRun(TestRunner.java:767) 
     ... 

通過覆蓋的toString(),我看到這些日誌中(有我的評語),但報告沒有更新

[2013-03-05 14:53:22,174] (Main.java:30) - calling execute 
    [2013-03-05 14:53:22,346] GenericFunctionTest.<init>(GenericFunctionTest.java:52) - inside constructor 
    [2013-03-05 14:53:22,372] GenericFunctionTest.toString(GenericFunctionTest.java:276) - returning **//this followed by 3 invocations before arriving at @Test method** 
    [2013-03-05 14:53:22,410] GenericFunctionTest.toString(GenericFunctionTest.java:276) - returning 
    [2013-03-05 14:53:22,416] GenericFunctionTest.toString(GenericFunctionTest.java:276) - returning 
    [2013-03-05 14:53:22,455] GenericFunctionTest.toString(GenericFunctionTest.java:276) - returning 
    [2013-03-05 14:53:22,892] GenericFunctionTest.<init>(GenericFunctionTest.java:52) - inside constructor 
    [2013-03-05 14:53:23,178] GenericFunctionTest.toString(GenericFunctionTest.java:276) - returning **//again blank as i havent set it yet** 
    [2013-03-05 14:53:23,182] GenericFunctionTest.getResult(GenericFunctionTest.java:69) - inside with test case:TestCase{signature=Signature{...}}**//I am setting it immedietely after this** 
    [2013-03-05 14:53:23,293] GenericFunctionTest.toString(GenericFunctionTest.java:276) - returning MyMethodName **//What i want** 
    [2013-03-05 14:53:23,299] GenericFunctionTest.toString(GenericFunctionTest.java:276) - returning MyMethodName **// again** 

編輯:再次被硬編碼的值,而不是把它放在入境嘗試了所有3我的測試方法。但相同的結果

+0

我使用TestNG的報表監聽器來觸發建立我的HTML出的iSuite結果的類做到這一點。要顯示測試報告中的任意數據(例如測試參數值),我認爲您必須爲每個測試的ITestContext添加數據,以便報告編寫者可以訪問其他數據。幸運的是,方法名稱已經是該上下文的一部分,您可以檢索它。 – djangofan 2014-01-22 23:01:25

回答

15

我有同樣的問題,並發現它有助於設置字段存儲測試用例名稱的方法註釋@BeforeMethod,使用native injection of TestNG提供方法名稱和測試參數。測試名稱取自DataProvider提供的測試參數。如果您的測試方法沒有參數,請報告方法名稱。

//oversimplified for demontration purposes 
public class TestParameters { 
    private String testName = null; 
    private String testDescription = null; 

    public TestParameters(String name, 
          String description) { 
     this.testName = name; 
     this.testDescription = description; 
    } 

    public String getTestName() { 
     return testName; 
    } 
    public String getTestDescription() { 
     return testDescription; 
    } 
} 

public class SampleTest implements ITest { 
    // Has to be set to prevent NullPointerException from reporters 
    protected String mTestCaseName = ""; 

    @DataProvider(name="BasicDataProvider") 
    public Object[][] getTestData() { 
     Object[][] data = new Object[][] { 
       { new TestParameters("TestCase1", "Sample test 1")}, 
       { new TestParameters("TestCase2", "Sample test 2")}, 
       { new TestParameters("TestCase3", "Sample test 3")}, 
       { new TestParameters("TestCase4", "Sample test 4")}, 
       { new TestParameters("TestCase5", "Sample test 5") } 
     }; 
     return data; 
    } 

    @BeforeMethod(alwaysRun = true) 
    public void testData(Method method, Object[] testData) { 
     String testCase = ""; 
     if (testData != null && testData.length > 0) { 
      TestParameters testParams = null; 
      //Check if test method has actually received required parameters 
      for (Object testParameter : testData) { 
       if (testParameter instanceof TestParameters) { 
        testParams = (TestParameters)testParameter; 
        break; 
       } 
      } 
      if (testParams != null) { 
       testCase = testParams.getTestName(); 
      } 
     } 
     this.mTestCaseName = String.format("%s(%s)", method.getName(), testCase); 
    } 

    @Override 
    public String getTestName() { 
     return this.mTestCaseName; 
    } 

    @Test(dataProvider="BasicDataProvider") 
    public void testSample1(TestParameters testParams){ 
     //test code here 
    } 

    @Test(dataProvider="BasicDataProvider") 
    public void testSample2(TestParameters testParams){ 
     //test code here 
    } 

    @Test 
    public void testSample3(){ 
     //test code here 
    } 
} 

編輯:基於下面的評論,我實現了從報告的樣本將是有益的。從上面的代碼運行報告

提取物:

<testng-results skipped="0" failed="0" total="5" passed="5"> 
    <suite name="SampleTests" duration-ms="2818" started-at="<some-time>" finished-at="<some-time>"> 
    <test name="Test1" duration-ms="2818" started-at="<some-time>" finished-at="<some-time>"> 
     <test-method 
      status="PASS" 
      signature="testSample1(org.example.test.TestParameters)[pri:0, instance:[email protected]]" 
      test-instance-name="testSample1(TestCase5)" 
      name="testSample1" 
      duration-ms="1014" 
      started-at="<some-time-before>" 
      data-provider="BasicDataProvider" 
      finished-at="<some-time-later>" > 
      <!-- excluded for demonstration purposes --> 
     </test-method> 
     <!-- the rest of test results excluded for brevity --> 
    </test> 
    </suite> 
</testng-result> 

注意,該值從getTestName()方法返回在屬性,而不是在name屬性。

+0

+1。我檢查了這一點,我可以在@BeforeMethod和getTestName()中的日誌中看到預期的名稱。但我沒有看到這反映在報告中。還有什麼可以做的嗎?任何配置更改?我的DataProvider是一個單獨的類。我也沒有創建一個TestParameters類。我從我的TestCase對象中提取所需的名稱。希望這些不會造成任何問題。 **正如我在我的qn中提到的,即使在getTestName()中硬編碼名稱也沒有反映出來。任何幫助表示讚賞 – rajesh 2013-03-12 12:18:18

+0

你在看哪個報告?如果您正在檢查TestNG XML報告,那麼您需要查找'test-instance-name'屬性。 – artdanil 2013-03-12 20:04:01

+0

我正在檢查html報告。是的,在XML中,test-instance-name會正確。但用戶正在檢查HTML報告。任何想法,如果這可以反映在那裏? – rajesh 2013-03-13 05:21:32

1

嘗試實施需要getTestName()方法的org.testng.ITest接口。 這種方式報告正確處理返回的值。

+0

這已經完成並在我的問題中解釋 – rajesh 2015-01-05 09:08:30

2

我遇到了類似的問題。首先我實現了已經提到的ITest策略。這是解決方案的一部分,但並不完全。

TestNG,出於某種原因,當構建不同的報告時,在構建報告時在測試中調用getName()。如果您沒有使用數據提供程序生成不同的運行並通過使用ITest策略爲每個運行設置唯一的名稱,那麼這很好。 如果您使用數據提供程序生成同一測試的多個運行並希望每次運行都具有唯一的名稱,則存在問題。 ITest策略將測試名稱作爲最後一次運行設置的名稱。

所以我不得不實現一個非常自定義的getName()。一些假設(在我的具體情況):

  1. 只有三個運行報告:TestHTMLReporter,EmailableReporter,XMLSuiteResultWriter。
  2. 當某個假設的記者沒有調用名字時,那麼返回當前設置的名字就沒有問題。
  3. 當記者正在運行時,它按順序進行getName()調用,每次運行只有一次。
public String getTestName() 
{ 
    String name = testName; 
    StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();//.toString(); 
    if(calledFrom(stackTrace, "XMLSuiteResultWriter")) 
    { 
     name = testNames.size()>0?testNames.get(xmlNameIndex<testNames.size()?xmlNameIndex:0):"undefined"; 
     xmlNameIndex++; 
     if(xmlNameIndex>=testNames.size()) 
      xmlNameIndex = 0; 
    } 
    else if(calledFrom(stackTrace, "EmailableReporter")) 
    { 
     name = testNames.size()>0?testNames.get(emailNameIndex<testNames.size()?emailNameIndex:0):"undefined"; 
     emailNameIndex++; 
     if(emailNameIndex>=testNames.size()) 
      emailNameIndex = 0; 
    } 
    if(calledFrom(stackTrace, "TestHTMLReporter")) 
    { 
     if(testNames.size()<0) 
     { 
      name = "undefined"; 
     } 
     else 
     { 
      if(htmlNameIndex < testNamesFailed.size()) 
      { 
       name = testNamesFailed.get(htmlNameIndex); 
      } 
      else 
      { 
       int htmlPassedIndex = htmlNameIndex - testNamesFailed.size(); 
       if(htmlPassedIndex < testNamesPassed.size()) 
       { 
        name = testNamesPassed.get(htmlPassedIndex); 
       } 
       else 
       { 
        name = "undefined"; 
       } 
      } 
     } 
     htmlNameIndex++; 
     if(htmlNameIndex>=testNames.size()) 
      htmlNameIndex = 0; 
    } 
    return name; 
} 

private boolean calledFrom(StackTraceElement[] stackTrace, String checkForMethod) 
{ 
    boolean calledFrom = false; 
    for(StackTraceElement element : stackTrace) 
    { 
     String stack = element.toString(); 
     if(stack.contains(checkForMethod)) 
      calledFrom = true; 
    } 
    return calledFrom; 
} 

當用於運行設置的名稱(我這樣做在@BeforeMethod(alwaysRun我定義= true)方法繼ITEST策略)加入我的名字到ArrayList testNames。但是,然後HTML報告是不正確的。大多數其他報告按順序提取信息,如XMLSuiteResultWriter,但TestHTMLReporter首先獲取失敗測試的所有名稱,然後獲取傳遞測試的名稱。所以我必須實現額外的ArrayLists:testNamesFailed和testNamesPassed,並根據測試是否通過,向測試名稱添加測試名稱。

我會毫不猶豫地承認這是非常非常脆弱的事情。理想情況下,TestNG在運行時將測試添加到集合中,並從該集合中獲取名稱,而不是從原始測試中獲取名稱。如果您有TestNG運行其他報告,您將不得不找出他們請求的名稱的順序以及什麼是在線程堆棧跟蹤中搜索的唯一足夠的字符串。

- 編輯1

或者,使用ITEST策略和工廠模式(@Factory註釋)。

TestNG Using @Factory and @DataProvider

http://beust.com/weblog/2004/09/27/testngs-factory/

它確實需要一些小的改動。這包括創建一個與原始測試方法具有相同參數的構造函數。測試方法現在沒有參數。您可以在新的構造函數中設置該名稱,並簡單地在getTestName方法中返回該名稱。確保從測試方法中刪除數據提供者規範。

2

如果您想更改HTML報告中的名稱,這將是一個徹頭徹尾的破解。 我是這樣做的:

public class NinjaTest { 
... 
... 
@AfterMethod (alwaysRun = true) 
public void afterMethod(ITestResult result, Method method) { 
    try { 
     //I have XML test suites organized in directories. 
     String xmlFile = result.getTestContext().getCurrentXmlTest().getSuite().getFileName(); 
     String suiteName = xmlFile.substring(xmlFile.lastIndexOf("\\") + 1, xmlFile.lastIndexOf(".xml")); 
     String pathToFile = xmlFile.substring(0, xmlFile.lastIndexOf("\\")); 
     String directory = pathToFile.substring(pathToFile.lastIndexOf("\\") + 1); 
     String testMethodName = String.format("%s/%s - %s", directory, suiteName, method.getName()); 

     //Total hack to change display name in HTML report \(^o^)/ 
     Field methodName = org.testng.internal.BaseTestMethod.class.getDeclaredField("m_methodName"); 
     methodName.setAccessible(true); 
     methodName.set(result.getMethod(), testMethodName); 
    } catch (Exception e) { 
     // Eh.... ¯\_(ツ)_/¯ 
     e.printStackTrace(); 
    } 
} 
... 
... 
相關問題