TestNG - Run each instance from TestNG factory as separate test - testing

I am using TestNG for test automation along with ReportNG for reporting. I use a TestNG factory class to provide different inputs for my tests. The problem which I face here is that all test instances supplied by the factory run under the same test, and the report generated displays all the scenarios under a single test.
I want to run each test instance supplied by the factory as a separate test. Is there any way to do this? PFB my xml configuration
<suite name="Default suite" parallel="classes">
<listeners>
<listener class-name="org.uncommons.reportng.HTMLReporter" />
</listeners>
<test verbose="2" name="Default test" group-by-instances="true">
<classes>
<class name="com.test.factory.RAExcelFactory"/>
</classes>
</test> <!-- Default test -->
</suite> <!-- Default suite -->

No this is not possible currently in TestNG.
Alternately you can consider doing the following instead of using a factory.
Upgrade to latest TestNG version
Build an implementation of org.testng.IAlterSuiteListener and within it include logic to construct multiple <test> tags by using whatever logic you have within your Factory (am guessing it leverages a data driven mechanism)
Something like below
Test Class
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
public class StudentTest {
private int age;
#BeforeClass
#Parameters("age")
public void setup(int age) {
this.age = age;
}
#Test
public void firstTest() {
Assert.assertTrue(age >=0);
}
#Test(dependsOnMethods = "firstTest")
public void secondTest() {
Assert.assertTrue(age <= 125);
}
}
An IAlterSuiteListener implementation
import org.testng.IAlterSuiteListener;
import org.testng.xml.XmlClass;
import org.testng.xml.XmlSuite;
import org.testng.xml.XmlTest;
import java.util.ArrayList;
import java.util.List;
public class SuiteAlteringListener implements IAlterSuiteListener {
#Override
public void alter(List<XmlSuite> suites) {
for (XmlSuite suite : suites) {
List<XmlTest> tests = new ArrayList<>();
Integer[] datum = getData();
for (Integer data : datum) {
XmlTest test = new XmlTest(suite);
test.setName("test_" + data);
test.addParameter("age", Integer.toString(data));
test.getClasses().add(new XmlClass(StudentTest.class));
}
}
}
private Integer[] getData() {
//Change this to your data provider implementation
return new Integer[]{
1, 2, 3
};
}
}
The suite xml file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="my_suite" parallel="false" verbose="3">
<listeners>
<listener class-name="com.rationaleemotions.stackoverflow.SuiteAlteringListener"/>
</listeners>
</suite>
and here's how the testng-results.xml looks like (The other reports would have similar details as well). I am just choosing to attach the easiest representation.
<?xml version="1.0" encoding="UTF-8"?>
<testng-results skipped="0" failed="0" ignored="0" total="6" passed="6">
<reporter-output>
</reporter-output>
<suite name="my_suite" duration-ms="10077" started-at="2017-05-27T07:49:36Z" finished-at="2017-05-27T07:49:46Z">
<groups>
</groups>
<test name="test_1" duration-ms="24" started-at="2017-05-27T07:49:36Z" finished-at="2017-05-27T07:49:36Z">
<class name="com.rationaleemotions.stackoverflow.StudentTest">
<test-method status="PASS" signature="setup(int)[pri:0, instance:com.rationaleemotions.stackoverflow.StudentTest#61dc03ce]" name="setup" is-config="true" duration-ms="8" started-at="2017-05-27T13:19:36Z" finished-at="2017-05-27T13:19:36Z">
<params>
<param index="0">
<value>
<![CDATA[1]]>
</value>
</param>
</params>
<reporter-output>
</reporter-output>
</test-method> <!-- setup -->
<test-method status="PASS" signature="firstTest()[pri:0, instance:com.rationaleemotions.stackoverflow.StudentTest#61dc03ce]" name="firstTest" duration-ms="2" started-at="2017-05-27T13:19:36Z" finished-at="2017-05-27T13:19:36Z">
<reporter-output>
</reporter-output>
</test-method> <!-- firstTest -->
<test-method status="PASS" signature="secondTest()[pri:0, instance:com.rationaleemotions.stackoverflow.StudentTest#61dc03ce]" name="secondTest" duration-ms="1" started-at="2017-05-27T13:19:36Z" depends-on-methods="com.rationaleemotions.stackoverflow.StudentTest.firstTest" finished-at="2017-05-27T13:19:36Z">
<reporter-output>
</reporter-output>
</test-method> <!-- secondTest -->
</class> <!-- com.rationaleemotions.stackoverflow.StudentTest -->
</test> <!-- test_1 -->
<test name="test_2" duration-ms="2" started-at="2017-05-27T07:49:41Z" finished-at="2017-05-27T07:49:41Z">
<class name="com.rationaleemotions.stackoverflow.StudentTest">
<test-method status="PASS" signature="setup(int)[pri:0, instance:com.rationaleemotions.stackoverflow.StudentTest#458ad742]" name="setup" is-config="true" duration-ms="0" started-at="2017-05-27T13:19:41Z" finished-at="2017-05-27T13:19:41Z">
<params>
<param index="0">
<value>
<![CDATA[2]]>
</value>
</param>
</params>
<reporter-output>
</reporter-output>
</test-method> <!-- setup -->
<test-method status="PASS" signature="firstTest()[pri:0, instance:com.rationaleemotions.stackoverflow.StudentTest#458ad742]" name="firstTest" duration-ms="0" started-at="2017-05-27T13:19:41Z" finished-at="2017-05-27T13:19:41Z">
<reporter-output>
</reporter-output>
</test-method> <!-- firstTest -->
<test-method status="PASS" signature="secondTest()[pri:0, instance:com.rationaleemotions.stackoverflow.StudentTest#458ad742]" name="secondTest" duration-ms="0" started-at="2017-05-27T13:19:41Z" depends-on-methods="com.rationaleemotions.stackoverflow.StudentTest.firstTest" finished-at="2017-05-27T13:19:41Z">
<reporter-output>
</reporter-output>
</test-method> <!-- secondTest -->
</class> <!-- com.rationaleemotions.stackoverflow.StudentTest -->
</test> <!-- test_2 -->
<test name="test_3" duration-ms="2" started-at="2017-05-27T07:49:46Z" finished-at="2017-05-27T07:49:46Z">
<class name="com.rationaleemotions.stackoverflow.StudentTest">
<test-method status="PASS" signature="setup(int)[pri:0, instance:com.rationaleemotions.stackoverflow.StudentTest#66d2e7d9]" name="setup" is-config="true" duration-ms="0" started-at="2017-05-27T13:19:46Z" finished-at="2017-05-27T13:19:46Z">
<params>
<param index="0">
<value>
<![CDATA[3]]>
</value>
</param>
</params>
<reporter-output>
</reporter-output>
</test-method> <!-- setup -->
<test-method status="PASS" signature="firstTest()[pri:0, instance:com.rationaleemotions.stackoverflow.StudentTest#66d2e7d9]" name="firstTest" duration-ms="0" started-at="2017-05-27T13:19:46Z" finished-at="2017-05-27T13:19:46Z">
<reporter-output>
</reporter-output>
</test-method> <!-- firstTest -->
<test-method status="PASS" signature="secondTest()[pri:0, instance:com.rationaleemotions.stackoverflow.StudentTest#66d2e7d9]" name="secondTest" duration-ms="0" started-at="2017-05-27T13:19:46Z" depends-on-methods="com.rationaleemotions.stackoverflow.StudentTest.firstTest" finished-at="2017-05-27T13:19:46Z">
<reporter-output>
</reporter-output>
</test-method> <!-- secondTest -->
</class> <!-- com.rationaleemotions.stackoverflow.StudentTest -->
</test> <!-- test_3 -->
</suite> <!-- my_suite -->
</testng-results>
Would this work for you ?

Related

in testng.xml run as testng suit triggers IE browser & run each test manually it runs with chrome. Why so?

when i run with testng.xml then IE browser opens with the message "This is the initial start page for the WebDriver server."
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "testng.org/testng-1.0.dtd"> <suite name="abc"> <groups> <run> <!-- include name = "HC"></include> --> <!--include name = "Reg"></include> --> <include name = "test"></include> </run> </groups> <test name="regression"> <classes> <class name="A"></class> <class name="B"></class> <class name="C"></class> </classes> </test> </suite> <!-- Suite -->

When a #BeforeTest method fails, why is it not being listed in the testng-failed.xml?

I am using maven with testng 6.14.3.
Here is my code structure:
testng.xml
<?xml version="1.0" encoding="UTF-8"?>
<suite name="set-3" parallel="tests" thread-count="10">
<listeners>
<listener class-name="org.uncommons.reportng.HTMLReporter" />
</listeners>
<test name="Customer Tests">
<groups>
<run>
<include name="abc"/>
</run>
</groups>
<classes>
<class name="apps.Test1_BeforeTest_Of_Test2"></class>
<class name="apps.Test2"></class>
</classes>
</test>
</suite>
Test1_BeforeTest_Of_Test2.java
public class Test1_BeforeTest_Of_Test2{
#BeforeTest(groups = {"abc"})
public void test1Method() throws Exception {
}
#AfterTest(groups={"abc"})
public void test1AfterMethod() throws Exception {
}
}
Test2.java
public class Test2{
#Test(groups = {"abc"})
public void test2Method(){
}
}
During my run, Test1_BeforeTest_Of_Test2 class fails. So, Test2 is marked as skipped.
But, when I look at the testng-failed.xml that is generated at the end of the run, the failed #BeforeTest class (Test1_BeforeTest_Of_Test2) is not included/listed:
testng-failed.xml
<?xml version="1.0" encoding="UTF-8"?>
<suite thread-count="10" name="Failed suite [set-3]" parallel="tests">
<listeners>
<listener class-name="org.uncommons.reportng.HTMLReporter"/>
</listeners>
<test name="Customer Tests(failed)">
<groups>
<run>
<include name="abc"/>
</run>
</groups>
<classes>
<class name="apps.Test2">
<methods>
<include name="test2Method"/>
</methods>
</class>
</classes>
</test>
</suite>
Is this expected behaviour? Or a bug/gap in testng-failed.xml?
Ideally, when we re-run the failed tests, we expect the #BeforeTest to run as well, because it is pre-req for Test 2.
TestNG currently seems to be honouring configurations to be considered in the testng-failed.xml if its part of the skipped test method's test class i.e., the configuration (which is perhaps what has caused a test to be skipped) needs to reside in the same java class as your skipped method for TestNG to consider it to be included.
In your example, that's not the case and the configuration method exists in a different test class (which is perfectly valid).
This looks like a bug in TestNG to me.
I have submitted a bug on your behalf on the TestNG project and will get it fixed in the upcoming version (7.5.0).
Defect : https://github.com/cbeust/testng/issues/2611

Test method not run with sequence in testng

I am using TestNG + WebDriver for my automation project but order of test execution is not working as expected have specified the order for each method below is the method signature and notation
#Test(dependsOnMethods="verifyElementsOnProfileScreen",alwaysRun = true)
public void verifyMySelfProfileVisibility(){
TestSuit the I have using :
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="regressionSuite" parallel="none">
<parameter name="ApplicationOpt" value="web"></parameter>
<parameter name="Browser" value="firefox"></parameter>
<test name="Test">
<classes>
<!-- Login Module -->
<class name="Tests.Login.LoginApp"/>
<method>
<include name ="loginUser"></include>
</method>
<!-- Portal Module -->
<class name="Tests.Profile.ProfileModule">
<method>
<include name="verifyElementsOnProfileScreen"></include>
<include name="verifyMySelfProfileVisibility"></include>
</method>
</class>
<class name="Tests.Profile.participantAuditLog">
<method>
<include name="verifyAuditLogForCreateProfileEvent"></include>
<include name="verifyAuditLogForUpdateContactInfoEvnet"></include>
<include name="verifyAuditLogForUpdatePrivacyDirective"></include>
</method>
</class>
</classes>
</test> <!-- Test -->
</suite> <!-- regressionSuite -->
Do you mean Classes which specified in testng.xml file not executing in specified order.. then please use preserve-order= "true"
<suite name="MySuite" preserve-order= "true">
<test name="MyTest">
If you want to specify order of methods execution in Class then use priority
#Test( priority = 1 )
group-by-instances="true" also useful if you face situation like execution order of priority methods of different classes are not as expected..
<suite thread-count="2" verbose="10" name="testSuite" parallel="tests">
<test verbose="2" name="MytestCase" group-by-instances="true">
Thank You,
Murali

TestNG DataProvider reading test data from the testng.xml config file?

Is it possible for a TestNG DataProvider to read test data from the testng.xml config file? Or is this unrealistic for some reason? I would like to be able to read test data from that file at the suite level and class level.
So, given a testing.xml file like this (which I am unsure is realistic or not), how would I do this? I have written a DataProvider using XStream (or Jackson) before and so I am well versed in my own custom .xml format, but sticking to the strict format of the testing.xml is where I am worried about this.
The following testing.xml is obvious invalid but I am just trying to show the kind of thing I would like to do:
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="TestAll">
<parameter name="hubUrl" value="http://localhost:4444/wd/hub"/>
<parameter name="reportFile" value="CustomReport.html"/>
<test name="etsy">
<parameter name="reportFile" value="CustomReport.html"/>
<classes>
<class name="qa.examples.suite.TestSearch">
<parameter name="appUrl" value="http://etsy.com" type="java.lang.String"/>
<parameter name="browser" value="Firefox" type="java.lang.String"/>
<parameter name="testEnabled" value="true" type="java.lang.Boolean"/>
<methods>
<include name="testEtsySearch"/>
<tests>
<test>
<parameter name="testNum" value="1" type="java.lang.Integer"/>
<parameter name="searchTerm" value="cell phone" type="java.lang.String"/>
<parameter name="searchTerm" value="batteries" type="java.lang.String"/>
</test>
<test>
<parameter name="testNum" value="2" type="java.lang.Integer"/>
<parameter name="searchTerm" value="buttons" type="java.lang.String"/>
<parameter name="searchTerm" value="metal" type="java.lang.String"/>
</test>
</tests>
</include>
</methods>
</class>
<class name="qa.examples.suite.TestFilters" />
</classes>
</test>
</suite>
So, is something like this possible? If so, how would you do it?
Try to pass ITestContext as a data provider parameter.
Something like:
#DataProvider(name = "DataProvider")
public static Object[][] Provider(ITestContext context) throws Exception
{
String dataFile = context.getCurrentXmlTest().getParameter("dataFile");
}
Suite xml
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="suite">
<parameter name="param1" value="val1"/>
<test name="test">
<parameter name="param2" value="val2"/>
<classes>
<class name="test.TestClass1" />
</classes>
</test>
</suite>
test class
package test;
import java.util.Map;
import org.testng.ITestContext;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class TestClass1 {
#DataProvider(name="Provider")
public Object[][] provider(ITestContext context)
{
Map<String, String> testParams = context.getCurrentXmlTest().getLocalParameters();
Map<String, String> suiteParams=context.getCurrentXmlTest().getSuite().getParameters();
return new Object[][]{{suiteParams.get("param1"), testParams.get("param2")}};
}
#Test(dataProvider="Provider")
public void test1(String param1, String param2)
{
System.out.println("Param1: " + param1);
System.out.println("Param2: " + param2);
}
}
Output
[TestNG] Running:
/home/nightmare/workspace/test/suite.xml
Param1: val1
Param2: val2
===============================================
suite
Total tests run: 1, Failures: 0, Skips: 0
===============================================
I am currently passing only Suite Level Parameters from my XML. This is how I would do it -
I would create a class - readParamsFromXML.
#Parameters( { "suiteParam1", "suiteParam2" } )
#BeforeSuite
public void getSuiteLevelParamsFromXML(
#Optional("defaultValueForSuiteParam1")String SuiteParam1,
#Optional("defaultValueForSuiteParam2")String SuiteParam2 ) {
<Some Logic here based on the params passed>
}
I would extend a similar logic to read params at Test level & Method level by creating methods like - getTestLevelParamsFromXML & getMethodLevelParamsFromXML. I would add annotations like #BeforeClass & #BeforeMethod respectively for the above methods.
Now, all my test cases should extend readParamsFromXML class. This way - suite, test & class level parameters passed from XML could be available in test methods
Might not be the best way to get things done. But works perfectly for me.

Maven issue:Regarding Testng

I have a module A which runs through pom.xml and accesses a testng.xml which in turn calls a specific class.This class displays a list of things for the user to choose from.
I am taking the user value through bufferRead.The bufferRead does not detect the value entered by the User.
ie
Enter the test u want to run
1.Test1
2.Test2
3.Test3
1
(control never goes to the next line)
There goes my pom.xml
<suiteXmlFiles>
<suiteXmlFile>testng.xml</suiteXmlFile>
</suiteXmlFiles>`
This is my testng.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?><suite allow-return-values="false" configfailurepolicy="skip" data-provider-thread-count="10" group-by-instances="false" junit="false" name="Suite" parallel="false" preserve-order="true" skipfailedinvocationcounts="false" thread-count="5">
<test allow-return-values="false" group-by-instances="false" junit="false" name="Test" preserve-order="true" skipfailedinvocationcounts="false">
<classes>
<class name="com.org.Console1"<methods>
<include name="main" />
</methods>
</class>
</classes>
</test> <!-- Test -->
This is my java code that runs
System.out.println("Which tests do you want to run");
String input = bufferRead.readLine();