Custom test method name in TestNG reports

rajesh picture rajesh · Mar 5, 2013 · Viewed 28.9k times · Source

I am working on a project where I need to invoke TestNG programatically(using data providers). Things are fine except that in the report, we are getting the name of the @Test method, which is a generic one to handle many cases. What we would like is to get a meaningful name in the report.

I was researching on this and found 3 ways, but unfortunately, all are failing for me.

1) Implement ITest

I have found about this here and here

I am setting the name I want as soon as I enter the @Test method(For all 3 ways i tried,this is how I am setting the name).This name is returned from getTestName(). What i observed is that getTestName() is getting called before and after my @Test. Initially, it is returning null(for handling NullPointerException, I return "" instead of null) and later it returns correct value. But i dont see this getting reflected in the report

Edit:Also tried setting the name from@BeforeMethod as suggested by artdanil

2 and 3

Both are based on solutions given in the second link above

By overriding setName in XmlSuite, I am getting

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)
        ...

By overriding toString(), I see these in logs (with my comments) but no updates in report

[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**

Edit: tried again all 3 by hardcoding a value rather than setting it on entry of my test method. But same results

Answer

artdanil picture artdanil · Mar 11, 2013

I had the same problem, and found that it helps to set the field storing test case name in the method annotated with @BeforeMethod, using native injection of TestNG to provide method name and test parameters. The test name is taken from test parameters supplied by the DataProvider. If your test method does not have parameters, just report the method name.

//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
    }
}

EDIT: Based on the comments below, I realized a sample from report will be useful.

Extract from the report from running code above:

<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:org.example.test.TimeTest@c9d92c]"
            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>

Note, that the value returned from getTestName() method is in the test-instance-name attribute, and not in the name attribute.