How to Pass the features folder dynamically to a Jenkins->Maven->Testng Runner File

Viewed 454

In my jenkins pipeline I am invoking my test like

"mvn test -Drun_location=US"

And my pom.xml file looks like this

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.16</version>
    <configuration>
        <systemPropertyVariables>
            <run.location>${run_location}</run.location>
        </systemPropertyVariables>
        <suiteXmlFiles>
            <suiteXmlFile>${basedir}/testng.xml</suiteXmlFile>
        </suiteXmlFiles>
        <skipTests>false</skipTests>
        <testFailureIgnore>false</testFailureIgnore>
    </configuration>
</plugin>

And my testng.xml file looks like this

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite>
  <test>
  <parameter name="location" value="${run_location}"/>
   <classes>
      <class name="com.test.Runner_Jenkins"/>
    </classes>
  </test> 
</suite> 

I need to pass this parameter to my runner file to set the feature directory dynamically. How do I accomplish this.

@CucumberOptions (
features = {"features/${run_location}"},
glue = "StepDefinitions"
) 
1 Answers

There are two ways of achieving your requirement.

  1. You could use the build parameters of Jenkins and pass your run_location. Then using the Execute Shell script option that runs before the maven build, you could use the sed command to add this parameter to your pom.xml file, feature file, and testng.xml file. sed command replaces the existing text with new text. You could search google about the usage of sed command.
  2. The second option is to pass the run-location as a Jenkins build parameter. Then receive the build parameter inside your java code. Then add this run-location as a parameter to your testng xml file dynamically. This is called programmatic execution of testng. The below code will do this. The below code reads an existing testng XML file and adds a parameter based on your Jenkins input. In this way, you could receive this value inside any of your tests using the code mentioned below.

But this approach will not modify your pom.xml file and feature file. During the execution you have to figure out way to get this value to your code using java.

Programmatic execution of testng with dynamic jenkins parameter:

    String run_location = System.getProperty("run_location");

    TestNG tng = new TestNG();
    File initialFile = new File("testng.xml");
    InputStream inputStream = FileUtils.openInputStream(initialFile);
    Parser p = new Parser(inputStream);
    List<XmlSuite> suites = p.parseToList();
    List<XmlSuite> modifiedSuites = new ArrayList<>();
    for (XmlSuite suite : suites) {
        XmlSuite modifiedSuite = new XmlSuite();
        modifiedSuite.setParallel(suite.getParallel());
        modifiedSuite.setThreadCount(deviceNames.size());
        modifiedSuite.setName(suite.getName());
        modifiedSuite.setListeners(suite.getListeners());
        List<XmlTest> tests = suite.getTests();
        for (XmlTest test : tests) {
            for (int i = 0; i < deviceNames.size(); i++) {
                XmlTest modifedtest = new XmlTest(modifiedSuite);
                HashMap<String, String> parametersMap = new HashMap<>();
                parametersMap.put("run_location", run_location);
        
                modifedtest.setParameters(parametersMap);
                modifedtest.setXmlClasses(test.getXmlClasses());
            }
        }
        modifiedSuites.add(modifiedSuite);
    }
    inputStream.close();
    tng.setXmlSuites(modifiedSuites);
    tng.run(); 

Accessing the Parameter value inside your tests

   @Test
   @Parameters(value={"run_location"})
   public void executeBeforeTest(String runlocation){
    /**Your code goes her**/
   }
Related