我工作的一个项目,我需要以编程方式调用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()。 一些假设(在我的具体情况):
- 只有三个运行报告:TestHTMLReporter,EmailableReporter,XMLSuiteResultWriter。
- 当曾经得到的名字不叫的假设记者之一的结果,然后返回当前设置的名称是好的。
- 当记者正在运行,这使得它的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