テストレールにtestgnからテスト結果を投稿するとき、私は独自のテストケースのIDを管理する方法で問題に実行しています。
各方法はtestrailテストケースにマッピングされたので、私は、最初に、試験方法でそれらを格納されていました。私はテストメソッドをパラメータ化し始めるまでこれが働いていました。
今度は、私は、4つの異なるブラウザ上で単一のセレンのテストを実行し、個別に結果を保存したいとしましょう。四つの異なる結果が同一のテストケースに戻る報告するように私は、試験方法におけるケースIDを保存することができません。
その代わり、私は、.xmlファイルのパラメータとしてケースIDを追加しようとすることを決めました。この作品が、唯一の限り、あなたはクラスごとに単一のテストメソッドを持っているとして、それ以外の場合はtestXXX()とtestYYY()は、XMLの各エントリに同じIDを取得します。どちらかが運ので。
私は(そのようなパラメータを放棄、またはクラスごとに1つだけのテストメソッドを書くなど)の構造犠牲をせずに、すべてのテスト実行のすべてのバージョン用のケースの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システムであなたのTestCase IDを可視化する方法に依存します。
テストケースは、データ駆動型テストを表す場合、そのアプローチは少し異なることが必要です。
テストケースを定期的にテストを表す場合、私はあなたがすでに実用的なソリューションを持っていると信じています。
ここでは、これは終らの一つの方法です。私はTestNGの使用しています7.0.0-beta3
(今日の最新リリースバージョン)
仮定:
- TCMSにおけるAテストケースを表し、「n」は実際の試験の反復とパスであるとみなされる場合に限り、すべての反復は、そのAは失敗さもなければ、合格します。
従うべき手順:
- あなたは最初の特定のテストのTCMS(テストケース管理システム)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;
import java.util.concurrent.ConcurrentHashMap;
import org.testng.IInvokedMethod;
import org.testng.IInvokedMethodListener;
import org.testng.ITestResult;
public class TestRailReporter implements IInvokedMethodListener {
private Map<String, Boolean> resultTracker = new ConcurrentHashMap<>();
@Override
public void beforeInvocation(IInvokedMethod method, ITestResult testResult) {
String key = testResult.getInstanceName() + "." + method.getTestMethod().getMethodName();
resultTracker.putIfAbsent(key, Boolean.TRUE);
}
@Override
public void afterInvocation(IInvokedMethod method, ITestResult testResult) {
Tcms tcms =
method.getTestMethod().getConstructorOrMethod().getMethod().getAnnotation(Tcms.class);
// Only report those tests to TestRail wherein our annotation is found.
if (tcms == null) {
return;
}
if (method.getTestMethod().isDataDriven()) {
// For data driven tests we need a different logic
String key = testResult.getInstanceName() + "." + method.getTestMethod().getMethodName();
if (method.getTestMethod().hasMoreInvocation()) {
Boolean result = resultTracker.get(key);
result = result && (testResult.getStatus() == ITestResult.SUCCESS);
resultTracker.put(key, result);
return;
}
postResultsToTestRail(tcms, resultTracker.get(key));
} else {
postResultsToTestRail(tcms, testResult.getStatus() == ITestResult.SUCCESS);
}
}
private void postResultsToTestRail(Tcms tcms, boolean pass) {
String testCaseId = tcms.id();
// Write logic here that takes care of posting results to the TCMS system
System.err.println("Test case Id [" + testCaseId + "] passed ? " + pass);
}
}
サンプルテストケース:
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
@Listeners(TestRailReporter.class)
public class SampleTestCase {
@Test
@Tcms(id = "TESTRAIL-1")
public void testMethod() {
Assert.assertTrue(true);
}
@Test(dataProvider = "dp")
@Tcms(id = "TESTRAIL-2")
public void dataDrivenTestWithSomeFailures(int i) {
if (i % 2 == 0) {
Assert.fail("simulating a failure");
}
}
@Test(dataProvider = "dp")
@Tcms(id = "TESTRAIL-3")
public void dataDrivenTestWithNoFailures(int i) {
Assert.assertTrue(i >= 0);
}
@DataProvider(name = "dp")
public Object[][] getData() {
return new Object[][] {{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
注釈が使用されています:
import static java.lang.annotation.ElementType.METHOD;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target({METHOD})
public @interface Tcms {
String id() default "";
}
テストをデータ駆動型のため、データプロバイダによってテストメソッドに渡される引数は、以下のようになります。
import java.lang.annotation.Annotation;
public class TestData implements Tcms {
private String tcmsId;
private String data;
public TestData(String tcmsId, String data) {
this.tcmsId = tcmsId;
this.data = data;
}
@Override
public String id() {
return tcmsId;
}
public String getData() {
return data;
}
@Override
public Class<? extends Annotation> annotationType() {
return Tcms.class;
}
@Override
public String toString() {
return getData();
}
}
:以下のようなリスナーのルックス
import org.testng.IInvokedMethod;
import org.testng.IInvokedMethodListener;
import org.testng.ITestResult;
public class TestRailReporter2 implements IInvokedMethodListener {
@Override
public void afterInvocation(IInvokedMethod method, ITestResult testResult) {
if (method.getTestMethod().isDataDriven()) {
//Data driven tests need to be handled differently
Object[] parameters = testResult.getParameters();
if (parameters.length != 1) {
//If theres more than one parameter, then dont do anything.
return;
}
Object parameter = parameters[0];
if (!(parameter instanceof Tcms)) {
//If the parameter doesnt implement our interface dont do anything
return;
}
postResultsToTestRail(
(Tcms) parameter, testResult.getStatus() == ITestResult.SUCCESS, parameter.toString());
} else {
Tcms tcms =
method.getTestMethod().getConstructorOrMethod().getMethod().getAnnotation(Tcms.class);
if (tcms == null) {
return;
}
postResultsToTestRail(tcms, testResult.getStatus() == ITestResult.SUCCESS);
}
}
private void postResultsToTestRail(Tcms tcms, boolean pass) {
String testCaseId = tcms.id();
// Write logic here that takes care of posting results to the TCMS system
System.err.println("Test case Id [" + testCaseId + "] passed ? " + pass);
}
private void postResultsToTestRail(Tcms tcms, boolean pass, String param) {
String id = tcms.id();
// Write logic here that takes care of posting results to the TCMS system
System.err.println("Test case Id [" + id + "] with parameter [" + param + "] passed ? " + pass);
}
}
:以下のようなテストクラスのルックス
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
@Listeners(TestRailReporter2.class)
public class AnotherSampleTestCase {
@Test
@Tcms(id = "TESTRAIL-1")
public void simpleTestMethod() {
Assert.assertTrue(true);
}
@Test(dataProvider = "dp")
public void dataDrivenTestMethod(TestData data) {
Assert.assertFalse(data.getData().trim().isEmpty());
}
@DataProvider(name = "dp")
public Object[][] getData() {
return new Object[][] {
{new TestData("TESTRAIL-2", "Jack")},
{new TestData("TESTRAIL-3", "")},
{new TestData("TESTRAIL-4", "Daniels")}
};
}
}
ここでは、実行出力です:
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