Using variables as testng parameter values

489 views
Skip to first unread message

VanderRock s

unread,
Mar 8, 2022, 11:13:03 PM3/8/22
to testng-users
Can I use variables as parameter values for all my xml files. My scenario is as follows:
I use Appium with testng. As parameters to testng xml file, I submit the Android deviceName, Android platform number and Appium port number. I have several xml files for different groups of classes. Each of them have the same set of parameters. Instead of requiring the testers to enter this detail separately in each xml, my plan is to have a top level framework.properties file where the tester makes a one time note of his/her parameters and then I pull these into all of the required xml files. Is this possible?

My xml  file looks as follows:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="TP397_Procedure1">
  <test thread-count="5" name="Procedure1">
          <parameter name="TP_ID" value="TP397" />
        <parameter name="deviceName" value="R52N20ADN" />
        <parameter name="platformVersion" value="10" />
        <parameter name="portNumber" value="4723" />
    <classes>
      <class name="CPAutomationTestSuite.TP_000397.Procedure1.TP397_Procedure1_Initialize"/>
      <class name="CPAutomationTestSuite.TP_000397.Procedure1.TP397_Procedure1_Section01"/>
      <class name="CPAutomationTestSuite.TP_000397.Procedure1.TP397_Procedure1_Section02"/>

My framework.properties looks as follows:

appium.platformName = Android

appium.appPackage = Nalu.CP.Android

appium.automationName = uiautomator2

appium.appActivity = crc6429e3927486beccbc.ActivityLicenseBrowse

#appium.app =  D:\\Nalu.CP.Android_763.apk

appium.noReset = true

android.deviceName=

android.platformNumber=

appium.serverPort=
Reply all
Reply to author
Forward

⇜Krishnan Mahadevan⇝

unread,
Mar 9, 2022, 1:08:02 AM3/9/22
to testng-users
You can do the following:

  1. Make sure you are on the latest released version of TestNG (7.5 as of today)
  2. Build an implementation of IAlterSuiteListener
  3. Wire in this listener as a Service Provider Interface. Read more about it here
  4.  Within this listener read up your property file and then add them as parameters into each of the xml test objects as needed.
  5. For more information, please also refer to the javadocs of IAlterSuiteListener interface.
Below is a quick demo of what I am suggesting

import java.io.FileReader;
import java.io.IOException;
import java.util.List;
import java.util.Properties;
import org.testng.IAlterSuiteListener;
import org.testng.xml.XmlSuite;

public class ParameterInjector implements IAlterSuiteListener {

  @Override
  public void alter(List<XmlSuite> suites) {
    Properties properties = new Properties();
    try {
      properties.load(new FileReader("src/test/resources/file.properties"));
    } catch (IOException e) {
      throw new RuntimeException("Failed loading properties. Root cause: " + e.getMessage(), e);
    }

    suites.stream()
        .flatMap(each -> each.getTests().stream())
        .forEach(eachXmlTest -> properties.forEach(
            (key, value) -> eachXmlTest.addParameter(key.toString(), value.toString())));
  }
}
Java
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;

public class SampleTestCase {

  @Test
  @Parameters({"name", "skillset", "nickname", "alias"})
  public void myTestMethod(String name, String skillSet, String nickName, String alias) {
    String msg = String.format(
        "All hail %s also called as %s for your exceptional skills in %s. You are truly a %s",
        name, alias, skillSet, nickName);
    System.err.println(msg);
  }
}
Here's how the properties file looks like:
name=Po skillset=Martial arts nickname=Dragon-Warrior alias=KungFu-Panda





Thanks & Regards
Krishnan Mahadevan

"All the desirable things in life are either illegal, expensive, fattening or in love with someone else!"
My Scribblings @ http://wakened-cognition.blogspot.com/
My Technical Scribblings @ https://rationaleemotions.com/


--
You received this message because you are subscribed to the Google Groups "testng-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to testng-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/testng-users/3f501f61-0860-495f-b1d8-31d888ad9508n%40googlegroups.com.

VanderRock s

unread,
Mar 9, 2022, 11:34:09 AM3/9/22
to testng-users
Thank you @Krishnan. I have a question about the following statement in the link you provided

'Compile this file, then create a file at the location META-INF/services/org.testng.ITestNGListener, which will name the implementation(s) you want for this interface.'

I am using a maven project and my entire test framework and test scripts are in the src/test/java folder. I do not see any META-INF folder in the maven structure. How is this created or where is this located? 

Krishnan Mahadevan

unread,
Mar 9, 2022, 11:50:57 AM3/9/22
to testng...@googlegroups.com
Please create it under src/test/resources 

Thanks & Regards
Krishnan Mahadevan

"All the desirable things in life are either illegal, expensive, fattening or in love with someone else!"

From: testng...@googlegroups.com <testng...@googlegroups.com> on behalf of VanderRock s <vander...@gmail.com>
Sent: Wednesday, March 9, 2022 10:04:09 PM
To: testng-users <testng...@googlegroups.com>
Subject: Re: [testng-users] Using variables as testng parameter values
 

VanderRock s

unread,
Mar 9, 2022, 1:25:35 PM3/9/22
to testng-users
Sorry this portion is not too clear either in the following link https://testng.org/doc/documentation-main.html#listeners-service-loader:

Compile this file, then create a file at the location META-INF/services/org.testng.ITestNGListener, which will name the implementation(s) you want for this interface.

You should end up with the following directory structure, with only two files:


$ tree

|____META-INF

| |____services

| | |____org.testng.ITestNGListener

|____test

| |____tmp

| | |____TmpSuiteListener.class

 

$ cat META-INF/services/org.testng.ITestNGListener

test.tmp.TmpSuiteListener


I created the META-INF/services under src/test/resources. I tried copying the org.TestNG.ITestNGListener from Maven dependencies to this 'services' folder but that copy is not allowed in Eclipse. What exactly does 'Compile this file, then create a file at the location META-INF/services/org.testng.ITestNGListener, which will name the implementation(s) you want for this interface' mean I should be doing?

Also, I compiled the ParameterInjector class, but is the 'test/tmp' folder where I have to place the class file, also under  src/test/resources folder? I tried copying the class file to the location src/test/tesrources/test/tmp/  but only the java file gets copied over.


Also for the following step:

Create a jar of this directory:

$ jar cvf ../sl.jar .

added manifest

ignoring entry META-INF/

adding: META-INF/services/(in = 0) (out= 0)(stored 0%)

adding: META-INF/services/org.testng.ITestNGListener(in = 26) (out= 28)(deflated -7%)

adding: test/(in = 0) (out= 0)(stored 0%)

adding: test/tmp/(in = 0) (out= 0)(stored 0%)

adding: test/tmp/TmpSuiteListener.class(in = 849) (out= 470)(deflated 44%)


Do i create a jar of the entire root folder or my project and place the jar in my project classpath? Somehow the steps assume deep knowledge of java, but from a tester perspective these things seems a little less intituive.

⇜Krishnan Mahadevan⇝

unread,
Mar 10, 2022, 1:51:29 AM3/10/22
to testng-users
Service Provider Interface is a Java concept and NOT a TestNG feature.

Have you tried reading about Service Provider Interface? That should clarify how to work with it.

The only thing that is specific to TestNG is the file name you use which is going to be "org.testng.ITestNGListener".
  1. mkdir -p src/test/resources/META-INF/services
  2. cd src/test/resources/META-INF/services
  3. touch org.testng.ITestNGListener
  4. vim org.testng.ITestNGListener
  5. Add all your listeners (1 entry per line) wherein you are including a Fully Qualified Class name of your listener implementation.

Thanks & Regards
Krishnan Mahadevan

"All the desirable things in life are either illegal, expensive, fattening or in love with someone else!"
My Scribblings @ http://wakened-cognition.blogspot.com/
My Technical Scribblings @ https://rationaleemotions.com/

Shruti

unread,
Mar 16, 2022, 2:14:16 PM3/16/22
to testng-users
Hi Krishnan,

I tried the above method but instead of service loaders I am calling the listener in my suite file. Just to give an idea, my suite files look as follows (you can see me calling the 'ParameterInjector' in each of these suites):
My properties file:
deviceName=R52N20ALVDN
platformVersion= 10
portNumber=4723

Parent suite:
    <suite name="TP397">  
          <listeners>
                <listener class-name="framework.Listeners.ParameterInjector" />
        </listeners>
    <suite-files>
        <suite-file path="./src/test/java/CPAutomationTestSuite/TP_000397/Procedure1/TP397_procedure1.xml"> </suite-file>
        <suite-file path="./src/test/java/CPAutomationTestSuite/TP_000397/Procedure2/TP397_procedure2.xml"> </suite-file>
        <suite-file path="./src/test/java/CPAutomationTestSuite/TP_000397/Procedure3/TP397_procedure3.xml"> </suite-file>
        <suite-file path="./src/test/java/CPAutomationTestSuite/TP_000397/Procedure4/TP397_procedure4.xml"> </suite-file>
    </suite-files>
</suite>


Child suite file 1:
<suite name="TP397_Procedure1">
        <listeners>
                <listener class-name="framework.ReportGenerator.ReporterManager" />
                <listener class-name="framework.Listeners.ParameterInjector" />
        </listeners>
        <test name="Procedure1">

                <parameter name="TP_ID" value="TP397" />
                <classes>
                        <class name="CPAutomationTestSuite.TP_000397.Procedure2.TP397_Procedure1_Initialize" />
                        <class name="CPAutomationTestSuite.TP_000397.Procedure2.TP397_Procedure1_Section01" />
                        <class name="CPAutomationTestSuite.TP_000397.Procedure2.TP397_Procedure1_Section02" />
                        <class name="CPAutomationTestSuite.TP_000397.Procedure2.TP397_Procedure1_Section03" />
                        <class name="CPAutomationTestSuite.TP_000397.Procedure2.TP397_Procedure1_TearDown" />
                </classes>
        </test> <!-- Procedure 2 -->
</suite> <!-- TP397_Procedure2 -->


Child suite file 2:
<suite name="TP397_Procedure2">
        <listeners>
                <listener class-name="framework.ReportGenerator.ReporterManager" />
                <listener class-name="framework.Listeners.ParameterInjector" />
        </listeners>
        <test name="Procedure2">

                <parameter name="TP_ID" value="TP397" />
                <classes>
                        <class name="CPAutomationTestSuite.TP_000397.Procedure2.TP397_Procedure2_Initialize" />
                        <class name="CPAutomationTestSuite.TP_000397.Procedure2.TP397_Procedure2_Section01" />
                        <class name="CPAutomationTestSuite.TP_000397.Procedure2.TP397_Procedure2_Section02" />
                        <class name="CPAutomationTestSuite.TP_000397.Procedure2.TP397_Procedure2_Section03" />
                        <class name="CPAutomationTestSuite.TP_000397.Procedure2.TP397_Procedure2_TearDown" />
                </classes>
        </test> <!-- Procedure 2 -->
</suite> <!-- TP397_Procedure2 -->


and so on...

Problem I am seeing in this approach, is that when I run the child suites, the runs go through fine, but when i run the parent suite, I see the following warning messages and the child scripts do not pick up the values from the properties file:

[RemoteTestNG] detected TestNG version 7.5.0
[main] WARN org.testng.TestNG - Ignoring duplicate listener : framework.Listeners.ParameterInjector
[main] WARN org.testng.TestNG - Ignoring duplicate listener : framework.Listeners.ParameterInjector
[main] WARN org.testng.TestNG - Ignoring duplicate listener : framework.Listeners.ParameterInjector
[main] WARN org.testng.TestNG - Ignoring duplicate listener : framework.Listeners.ParameterInjector

[INFO ] 2022-03-15 20:41:58 framework.Listeners.ExecutionListener 42 onExecutionStart -
***********************
TestNG Run Started
***********************

[INFO ] 2022-03-15 20:41:58 framework.commonUtilities.ExtentReports.ExtentListener 75 onExecutionStart - onStart called*****
[main] INFO org.testng.internal.Utils - [TestNG] Running:
  C:\Users\skhandekar\eclipse-workspace\CPAutomationFramework\src\test\java\CPAutomationTestSuite\TP_000397\Procedure1\TP397_Procedure1.xml

[INFO ] 2022-03-15 20:41:58 framework.Listeners.ExecutionListener 120 onStart -
********************************
Suite [TP397_Procedure1] started
********************************

[INFO ] 2022-03-15 20:41:58 framework.Listeners.ExecutionListener 220 onStart -

**********************************************************
***** Starting test - Procedure1 *****
**********************************************************

[INFO ] 2022-03-15 20:41:58 framework.testWriting.ResultWriter.ResultWriterCSV 45 <init> - FrameworkVariables.ALREADY_EXECUTED = false
[INFO ] 2022-03-15 20:41:58 framework.testWriting.ResultWriter.ResultWriterCSV 60 <init> - FrameworkVariables.ALREADY_EXECUTED = true
[INFO ] 2022-03-15 20:41:58 framework.Listeners.ExecutionListener 80 onBeforeClass -
**************************************************************
---------------------------------------------------------------
*****         Starting section - TP397_Procedure1_Section02         *****
---------------------------------------------------------------
***************************************************************

[INFO ] 2022-03-15 20:41:58 framework.testWriting.TestSection 166 setUpTest - BeforeMethod from TestSection
[INFO ] 2022-03-15 20:41:58 framework.testWriting.TestSection 215 setUpTest - Testname in TestSection is: TP397_001
[INFO ] 2022-03-15 20:41:58 framework.Listeners.ExecutionListener 149 beforeInvocation - BeforeInvocation: TP397_001
[INFO ] 2022-03-15 20:41:58 framework.Listeners.ExecutionListener 154 beforeInvocation -
*********************************************************************
Test Name - TP397_001
Description: Creating OR Session With ETM When IPG And Lead Details Are Configured
*********************************************************************

[INFO ] 2022-03-15 20:41:58 framework.commonUtilities.ExtentReports.ExtentListener 194 beforeInvocation - Test started - from extent reports
[INFO ] 2022-03-15 20:41:58 framework.testWriting.ResultWriter.ResultWriterCSV 219 appendTestCaseResultToCSV -
**********************************************
Write TestCase result to ResultReport
**********************************************

[INFO ] 2022-03-15 20:41:58 framework.testWriting.ResultWriter.ResultWriterCSV 315 appendToCSV - StringArray:
[INFO ] 2022-03-15 20:41:58 framework.testWriting.ResultWriter.ResultWriterCSV 315 appendToCSV - StringArray: TP397_001_Completed
[INFO ] 2022-03-15 20:41:58 framework.testWriting.ResultWriter.ResultWriterCSV 315 appendToCSV - StringArray:
[INFO ] 2022-03-15 20:41:58 framework.testWriting.ResultWriter.ResultWriterCSV 315 appendToCSV - StringArray:
[INFO ] 2022-03-15 20:41:58 framework.testWriting.ResultWriter.ResultWriterCSV 315 appendToCSV - StringArray:
[INFO ] 2022-03-15 20:41:58 framework.testWriting.ResultWriter.ResultWriterCSV 315 appendToCSV - StringArray:
[INFO ] 2022-03-15 20:41:58 framework.testWriting.ResultWriter.ResultWriterCSV 315 appendToCSV - StringArray: Fail
[INFO ] 2022-03-15 20:41:58 framework.testWriting.ResultWriter.ResultWriterCSV 315 appendToCSV - StringArray:
[INFO ] 2022-03-15 20:41:58 framework.testWriting.ResultWriter.ResultWriterCSV 319 appendToCSV - WRITE NEXT: [, TP397_001_Completed, , , , , Fail, ]
[INFO ] 2022-03-15 20:41:58 framework.testWriting.ResultWriter.ResultWriterCSV 223 appendTestCaseResultToCSV - WRITE NEXT: [, TP397_001_Completed, Fail]
[ERROR] 2022-03-15 20:41:58 framework.Listeners.ExecutionListener 203 onTestSkipped - [TestSection.initialize(java.lang.String,java.lang.String,java.lang.String)[pri:0, instance:CPAutomationTestSuite.TP_000397.Procedure1.TP397_Procedure1_Section02@ffaa6af]]
[ERROR] 2022-03-15 20:41:58 framework.Listeners.ExecutionListener 204 onTestSkipped -
***********************************************************************************************************************************
Skipped Test Name = TP397_001, was skipped due to:
[framework.testWriting.TestSection.initialize] which is a configuration Method.
 
 org.testng.TestNGException:
Parameter 'deviceName' is required by BeforeClass on method initialize but has not been marked @Optional or defined
in C:\Users\skhandekar\eclipse-workspace\CPAutomationFramework\src\test\java\CPAutomationTestSuite\TP_000397\Procedure1\TP397_Procedure1.xml

***********************************************************************************************************************************

Any reason how to fix this?

Shruti

unread,
Mar 16, 2022, 2:19:40 PM3/16/22
to testng-users
I also tried removing the listener from parent testng xml but still face the same warning messages and problems. My requirement is that user should be able to either run all the suites through parent suite or run each of them individually, so it is important that listeners be present in both these types of  xml files.

⇜Krishnan Mahadevan⇝

unread,
Mar 17, 2022, 12:36:39 AM3/17/22
to testng-users
Shruti,

Those are just warnings from TestNG when it detects a duplicate listener being wired in.

This happens ONLY under the following circumstances:
  • You have a suite of suites
  • There are the same listeners that are being defined within your child suites (2 or more of them) or its common between the child and parent suite
This is because listeners are always global in nature in TestNG and they get hoisted to the global level after they are parsed from within the suite and the child suites.

If you need these listeners to be invoked irrespective of whether the user runs the test from within an IDE or from via a build tool using a suite xml, I would suggest that you make them as ServiceLoader powered ones because these listeners seem to be mandatory listeners and it's usually a very good practice to wire in the mandatory listeners via a service loader.

Thanks & Regards
Krishnan Mahadevan

"All the desirable things in life are either illegal, expensive, fattening or in love with someone else!"
My Scribblings @ http://wakened-cognition.blogspot.com/
My Technical Scribblings @ https://rationaleemotions.com/

Reply all
Reply to author
Forward
0 new messages