Java 使用testrail作为testng测试的报告器时发生ID冲突

Java 使用testrail作为testng测试的报告器时发生ID冲突,java,testng,testrail,Java,Testng,Testrail,当将测试结果从testgn发布到TestRail时,我遇到了如何管理唯一测试用例ID的问题 我最初将它们存储在测试方法中,因此每个方法都映射到一个testrail测试用例。在我开始参数化测试方法之前,这一直有效 现在假设我想在四种不同的浏览器上运行一个selenium测试,并分别存储结果。我无法在测试方法中存储案例id,因为四个不同的结果将报告回同一个测试案例 相反,我决定尝试将案例ID作为参数添加到.xml文件中。这是可行的,但前提是每个类只有一个测试方法,否则testXXX()和testYY

当将测试结果从testgn发布到TestRail时,我遇到了如何管理唯一测试用例ID的问题

我最初将它们存储在测试方法中,因此每个方法都映射到一个testrail测试用例。在我开始参数化测试方法之前,这一直有效

现在假设我想在四种不同的浏览器上运行一个selenium测试,并分别存储结果。我无法在测试方法中存储案例id,因为四个不同的结果将报告回同一个测试案例

相反,我决定尝试将案例ID作为参数添加到.xml文件中。这是可行的,但前提是每个类只有一个测试方法,否则testXXX()和testYYY()会为xml中的每个条目获取相同的id。所以那里也没有运气

我试图找到一种方法来为每个测试运行的每个版本存储案例ID,而不必牺牲结构(比如放弃参数,或者每个类只编写一个测试方法)

下面是一个示例套件

<suite name="UL" parallel="tests" thread-count="1" verbose="10">
    <parameter name="env" value="REDACTED"/>
    <parameter name="recordTests" value="1"/>
    <listeners>
    </listeners>
    <test name="UL Tests firefox">
        <classes>
            <class name="tests.selenium_tests.ULTests">
                <parameter name="browser" value="firefox"/>
                <parameter name="case_id" value="1111"/>
            </class>
        </classes>
    </test>
    <test name="UL Tests chrome">
        <classes>
            <class name="tests.selenium_tests.ULTests">
                <parameter name="browser" value="chrome"/>
                <parameter name="case_id" value="1112"/>
            </class>
        </classes>
    </test>
    <test name="UL Tests safari">
        <classes>
            <class name="tests.selenium_tests.ULTests">
                <parameter name="browser" value="bs_safari"/>
            </class>
        </classes>
    </test>
    <test name="UL Tests edge">
        <classes>
            <class name="tests.selenium_tests.ULTests">
                <parameter name="browser" value="bs_edge"/>
            </class>
        </classes>
    </test>
</suite>

这完全取决于您如何在TCMS系统中可视化您的测试用例ID

如果一个测试用例代表一个数据驱动的测试,那么这个方法需要稍微不同一些

如果一个测试用例代表一个常规测试,那么我相信您已经有了一个有效的解决方案

这里有一个方法来完成这件事。我使用的是TestNG
7.0.0-beta3
(最新发布版本,截至今日)

假设:

  • TCMS中的测试用例表示实际测试的“n”次迭代,当且仅当所有迭代都通过时,才视为通过,否则视为失败
应遵循的步骤:

  • 首先创建一个定制注释,该注释捕获特定测试的TCMS(Testcase管理系统)ID
  • 您可以使用自定义注释对
    @Test
    方法进行注释,以将其绑定到特定的TCMS测试用例
  • 现在,您可以构建一个自定义侦听器,确保它能够区分普通测试和数据驱动测试,并相应地发布结果。对于数据驱动的测试,他们需要跟踪到目前为止运行的所有迭代,然后计算总体结果
  • 我的博客文章也详细阐述了这一点

    下面是一个示例,它显示了所有这些功能:

    自定义注释如下所示:

    import static java.lang.annotation.ElementType.METHOD;
    import static java.lang.annotation.ElementType.TYPE;
    
    import java.lang.annotation.Retention;
    import java.lang.annotation.Target;
    
    @Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
    @Target({METHOD, TYPE})
    public @interface Tcms {
      String id() default "";
    }
    
    侦听器如下所示:

    import java.util.Map;
    导入java.util.concurrent.ConcurrentHashMap;
    导入org.testng.IInvokedMethod;
    导入org.testng.IInvokedMethodListener;
    导入org.testng.ITestResult;
    公共类TestRailReporter实现IInvokedMethodListener{
    私有映射resultTracker=新的ConcurrentHashMap();
    @凌驾
    调用前公共无效(IInvokedMethod方法,ITestResult testResult){
    String key=testResult.getInstanceName()+““+method.getTestMethod().getMethodName();
    结果tracker.putIfAbsent(key,Boolean.TRUE);
    }
    @凌驾
    调用后公共void(IInvokedMethod方法,ITestResult testResult){
    中药=
    方法.getTestMethod().getConstructorMethod().getMethod().getAnnotation(Tcms.class);
    //只向TestRail报告那些发现注释的测试。
    如果(tcms==null){
    返回;
    }
    if(method.getTestMethod().isDataDriven()){
    //对于数据驱动的测试,我们需要不同的逻辑
    String key=testResult.getInstanceName()+““+method.getTestMethod().getMethodName();
    if(method.getTestMethod().hasMoreInvocation()){
    布尔结果=resultTracker.get(键);
    结果=结果&(testResult.getStatus()==ITestResult.SUCCESS);
    结果tracker.put(键、结果);
    返回;
    }
    postResultsToTestRail(tcms,resultTracker.get(key));
    }否则{
    postResultsToTestRail(tcms,testResult.getStatus()==ITestResult.SUCCESS);
    }
    }
    私有void postResultsToTestRail(Tcms Tcms,布尔传递){
    字符串testCaseId=tcms.id();
    //在此处写入用于将结果发布到TCMS系统的逻辑
    System.err.println(“测试用例Id[“+testCaseId+”]passed?”+pass);
    }
    }
    
    示例测试用例:

    import org.testng.Assert;
    导入org.testng.annotations.DataProvider;
    导入org.testng.annotations.Listeners;
    导入org.testng.annotations.Test;
    @侦听器(TestRailReporter.class)
    公共类SampleTestCase{
    @试验
    @Tcms(id=“TESTRAIL-1”)
    公共void testMethod(){
    Assert.assertTrue(true);
    }
    @测试(dataProvider=“dp”)
    @Tcms(id=“TESTRAIL-2”)
    带有某些故障的公共无效DataDrivenTest(int i){
    如果(i%2==0){
    Assert.fail(“模拟失败”);
    }
    }
    @测试(dataProvider=“dp”)
    @Tcms(id=“TESTRAIL-3”)
    公共无效dataDrivenTestWithNoFailures(int i){
    Assert.assertTrue(i>=0);
    }
    @数据提供者(name=“dp”)
    公共对象[][]获取数据(){
    返回新对象[][{1},{2},{3};
    }
    }
    
    输出:

    Test case Id [TESTRAIL-3] passed ? true
    Test case Id [TESTRAIL-2] passed ? false
    
    
    java.lang.AssertionError: simulating a failure
    
        at org.testng.Assert.fail(Assert.java:97)
        at com.rationaleemotions.stackoverflow.qn54224337.SampleTestCase.dataDrivenTestWithSomeFailures(SampleTestCase.java:21)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:131)
        at org.testng.internal.TestInvoker.invokeMethod(TestInvoker.java:570)
        at org.testng.internal.TestInvoker.invokeTestMethod(TestInvoker.java:170)
        at org.testng.internal.MethodRunner.runInSequence(MethodRunner.java:46)
        at org.testng.internal.TestInvoker$MethodInvocationAgent.invoke(TestInvoker.java:790)
        at org.testng.internal.TestInvoker.invokeTestMethods(TestInvoker.java:143)
        at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:146)
        at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:128)
        at org.testng.TestRunner.privateRun(TestRunner.java:763)
        at org.testng.TestRunner.run(TestRunner.java:594)
        at org.testng.SuiteRunner.runTest(SuiteRunner.java:398)
        at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:392)
        at org.testng.SuiteRunner.privateRun(SuiteRunner.java:355)
        at org.testng.SuiteRunner.run(SuiteRunner.java:304)
        at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:53)
        at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:96)
        at org.testng.TestNG.runSuitesSequentially(TestNG.java:1146)
        at org.testng.TestNG.runSuitesLocally(TestNG.java:1067)
        at org.testng.TestNG.runSuites(TestNG.java:997)
        at org.testng.TestNG.run(TestNG.java:965)
        at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:73)
        at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:123)
    
    Test case Id [TESTRAIL-1] passed ? true
    
    ===============================================
    Default Suite
    Total tests run: 7, Passes: 6, Failures: 1, Skips: 0
    ===============================================
    
    编辑:根据OP的评论,这里是另一种方法

    方法2

    正在使用的注释:

    导入静态java.lang.annotation.ElementType.METHOD;
    导入java.lang.annotation.Retention;
    导入java.lang.annotation.Target;
    @保留(java.lang.annotation.RetentionPolicy.RUNTIME)
    @目标({METHOD})
    公共@接口Tcms{
    字符串id()默认为“”;
    }
    
    对于数据驱动测试,数据提供程序将传递给测试方法的参数如下所示:

    import java.lang.annotat
    
    Test case Id [TESTRAIL-2] with parameter [Jack] passed ? true
    Test case Id [TESTRAIL-3] with parameter [] passed ? false
    
    java.lang.AssertionError: did not expect to find [false] but found [true]
    
        at org.testng.Assert.fail(Assert.java:97)
        at org.testng.Assert.failNotEquals(Assert.java:969)
        at org.testng.Assert.assertFalse(Assert.java:65)
        at org.testng.Assert.assertFalse(Assert.java:75)
        at com.rationaleemotions.stackoverflow.qn54224337.AnotherSampleTestCase.dataDrivenTestMethod(AnotherSampleTestCase.java:19)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:131)
        at org.testng.internal.TestInvoker.invokeMethod(TestInvoker.java:570)
        at org.testng.internal.TestInvoker.invokeTestMethod(TestInvoker.java:170)
        at org.testng.internal.MethodRunner.runInSequence(MethodRunner.java:46)
        at org.testng.internal.TestInvoker$MethodInvocationAgent.invoke(TestInvoker.java:790)
        at org.testng.internal.TestInvoker.invokeTestMethods(TestInvoker.java:143)
        at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:146)
        at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:128)
        at org.testng.TestRunner.privateRun(TestRunner.java:763)
        at org.testng.TestRunner.run(TestRunner.java:594)
        at org.testng.SuiteRunner.runTest(SuiteRunner.java:398)
        at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:392)
        at org.testng.SuiteRunner.privateRun(SuiteRunner.java:355)
        at org.testng.SuiteRunner.run(SuiteRunner.java:304)
        at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:53)
        at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:96)
        at org.testng.TestNG.runSuitesSequentially(TestNG.java:1146)
        at org.testng.TestNG.runSuitesLocally(TestNG.java:1067)
        at org.testng.TestNG.runSuites(TestNG.java:997)
        at org.testng.TestNG.run(TestNG.java:965)
        at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:73)
        at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:123)
    
    Test case Id [TESTRAIL-4] with parameter [Daniels] passed ? true
    Test case Id [TESTRAIL-1] passed ? true
    
    ===============================================
    Default Suite
    Total tests run: 4, Passes: 3, Failures: 1, Skips: 0
    ===============================================
    
    
    Process finished with exit code 0