TestNG中的自定义测试方法名称报告(Custom test method name in Tes

2019-07-20 23:58发布

我工作的一个项目,我需要以编程方式调用TestNG的(使用数据提供者)。 一切都很好,只是在报告中,我们所得到的是@Test方法,它是一个通用的一个处理很多案件的名称。 我们希望是在报告中获得一个有意义的名字。

我研究这个,发现3种方式,但不幸的是,所有的失败都是为我。

1)实施ITEST

我发现这个在这里和这里

我只要我进入@Test方法设置我想要的名称(对于所有3种方式我想,这是我如何设置的名称)。这个名字是从getTestName()返回。 我观察到的是getTestName()是越来越之前,我的@Test之后调用。 最初,它返回空值(用于处理NullPointerException异常,我返回“”,而不是零),随后又返回正确的值。 但我没有看到这个越来越反映在报告

编辑 :也尝试设置从@ BeforeMethod名称由artdanil的建议

图2和3

两者都是基于给定的解决方案上面的第二个链接

通过重写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。 但是,相同的结果

Answer 1:

我有同样的问题,并发现它有助于与注释的方法来设置字段存储测试用例名@BeforeMethod ,使用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: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>

请注意,该值从返回getTestName()方法是在test-instance-name属性,而不是在name属性。



Answer 2:

我遇到了类似的问题。 首先我实现已经提到的ITEST策略。 这是解决方案的一部分,但不是全部。

TestNG的,因为某些原因,建立不同的报告时,在测试调用的getName(),而建设的报告。 如果你不使用数据提供程序生成不同的运行,并为每个使用ITEST策略运行的唯一名称,这是好的。 如果您使用的是数据提供程序生成相同的测试的多次运行,并希望每次运行都有一个唯一的名称,然后还有一个问题。 由于ITEST策略离开了测试,通过上次运行设置的名称的名称。

所以我不得不实现一个非常定制的getName()。 一些假设(在我的具体情况):

  1. 只有三个运行报告:TestHTMLReporter,EmailableReporter,XMLSuiteResultWriter。
  2. 当曾经得到的名字不叫的假设记者之一的结果,然后返回当前设置的名称是好的。
  3. 当记者正在运行,这使得它的getName()为了呼吁,只有1对每个运行时间。
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;
}

当用于运行设置的名称加入我的名字到ArrayList testNames(I在(I所定义继ITEST策略alwaysRun = true)方法的@BeforeMethod这样做)。 但随后的HTML报告是不正确的。 大多数其他报告的拉动顺序的信息,如XMLSuiteResultWriter,但TestHTMLReporter首先得到了失败的测试,然后通过测试的名称所有名称得到名称。 所以我不得不执行额外的ArrayList:testNamesFailed和testNamesPassed,当考试结束基于他们是否通过或不添加测试的名字给他们。

我会坦率地承认这是一个很有黑客,非常脆弱。 理想的情况是,TestNG的增加了测试,以收集运行的同时,并从该集合,而不是从原来的测试得到的名称。 如果你有TestNG的运行其他报告,你将不得不找出他们要求什么样的顺序名字,什么是独特的足够字符串中的线程堆栈跟踪搜索。

- 编辑1

或者,使用ITEST策略和工厂模式(@Factory注释)。

TestNG的使用@Factory和@dataProvider

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

这确实需要一些小的改动。 这包括创建具有相同参数与原始测试方法的构造函数。 现在,测试方法没有参数。 您可以在新的构造函数中设置的名称和简单地返回,在getTestName方法。 确保从测试方法删除的数据提供的规范。



Answer 3:

如果你想在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();
    }
}
...
...


Answer 4:

请找到TestNG中报告测试用例集自定义名称下面的代码。

以下功能在这个代码是可用的。

  • 在多个时间相同的测试情况下的动态执行
  • 报表设置自定义测试用例的名字
  • 多的测试用例执行设置并行执行

     import java.lang.reflect.Field; import org.testng.ITest; import org.testng.ITestResult; import org.testng.Reporter; import org.testng.annotations.AfterMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Factory; import org.testng.annotations.Test; import org.testng.internal.BaseTestMethod; import com.test.data.ServiceProcessData; public class ServiceTest implements ITest { protected ServiceProcessData serviceProcessData; protected String testCaseName = ""; @Test public void executeServiceTest() { System.out.println(this.serviceProcessData.toString()); } @Factory(dataProvider = "processDataList") public RiskServiceTest(ServiceProcessData serviceProcessData) { this.serviceProcessData = serviceProcessData; } @DataProvider(name = "processDataList", parallel = true) public static Object[] getProcessDataList() { Object[] serviceProcessDataList = new Object[0]; //Set data in serviceProcessDataList return serviceProcessDataList; } @Override public String getTestName() { this.testCaseName = "User custom testcase name"; return this.testCaseName; } @AfterMethod(alwaysRun = true) public void setResultTestName(ITestResult result) { try { BaseTestMethod baseTestMethod = (BaseTestMethod) result.getMethod(); Field f = baseTestMethod.getClass().getSuperclass().getDeclaredField("m_methodName"); f.setAccessible(true); f.set(baseTestMethod, this.testCaseName); } catch (Exception e) { ErrorMessageHelper.getInstance().setErrorMessage(e); Reporter.log("Exception : " + e.getMessage()); } }} 

    谢谢



Answer 5:

尝试实现,需要一个getTestName()方法org.testng.ITest接口。 这样的报告正确处理返回值。



文章来源: Custom test method name in TestNG reports
标签: java testng