2013-03-05 139 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(); 
    } 
} 
... 
... 
相关问题