Java 使用testrail作为testng测试的报告器时发生ID冲突
当将测试结果从testgn发布到TestRail时,我遇到了如何管理唯一测试用例ID的问题 我最初将它们存储在测试方法中,因此每个方法都映射到一个testrail测试用例。在我开始参数化测试方法之前,这一直有效 现在假设我想在四种不同的浏览器上运行一个selenium测试,并分别存储结果。我无法在测试方法中存储案例id,因为四个不同的结果将报告回同一个测试案例 相反,我决定尝试将案例ID作为参数添加到.xml文件中。这是可行的,但前提是每个类只有一个测试方法,否则testXXX()和testYYY()会为xml中的每个条目获取相同的id。所以那里也没有运气 我试图找到一种方法来为每个测试运行的每个版本存储案例ID,而不必牺牲结构(比如放弃参数,或者每个类只编写一个测试方法) 下面是一个示例套件Java 使用testrail作为testng测试的报告器时发生ID冲突,java,testng,testrail,Java,Testng,Testrail,当将测试结果从testgn发布到TestRail时,我遇到了如何管理唯一测试用例ID的问题 我最初将它们存储在测试方法中,因此每个方法都映射到一个testrail测试用例。在我开始参数化测试方法之前,这一直有效 现在假设我想在四种不同的浏览器上运行一个selenium测试,并分别存储结果。我无法在测试方法中存储案例id,因为四个不同的结果将报告回同一个测试案例 相反,我决定尝试将案例ID作为参数添加到.xml文件中。这是可行的,但前提是每个类只有一个测试方法,否则testXXX()和testYY
<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”次迭代,当且仅当所有迭代都通过时,才视为通过,否则视为失败李>
@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