Tal Angel
Tal Angel

Reputation: 1788

How to run a test twice using TestNG

I am doing automation tests using TestNG and Maven. I need to run a single test twice, first running on one parameter (for example state=1) and later and the same parameter but with a another value (state=2).

I have a lot (more than 50) methods with @Test annotation. The idea is to make every test to be invoked w times, writing as less code as possible.

How to make my test run twice with this 2 states?

Upvotes: 1

Views: 2445

Answers (4)

murali selenium
murali selenium

Reputation: 3927

I prefer answer provided by Krishnan Mahadevan but if you think need to avoid coding then can use two <Test> in testng.xml file.

<test name="Test1" preserve-order="true">
    <parameter name="State" value="State1"></parameter>

    <classes>

        <class  name="class.here" />
 </classes>

</test> <!-- Test -->


 <test name="Test2" preserve-order="true">
    <parameter name="State" value="State2"></parameter>

    <classes>

        <class  name="class.here" />
 </classes>

</test> <!-- Test -->

So Test1 runs with one state and Test2 runs with another state.

use @Test(invocationCount = 2) to repeat the same test

Upvotes: 1

Neagu V
Neagu V

Reputation: 480

Use invocationCount - TESTNG

    @Test(invocationCount = 2)
    public void test() {
    }

The test above will be executed 2 times.

You can set invocationCount global if it is applicable for all the tests e.g.

public class InvocationCount implements IAnnotationTransformer {

@SuppressWarnings("rawtypes")
@Override
public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {
    annotation.setInvocationCount(Integer.parseInt(number_of_times_to_execute)));
}

Upvotes: 1

Krishnan Mahadevan
Krishnan Mahadevan

Reputation: 14746

Here's one way of doing this. Please feel free to expand this solution to whatever is your actual problem statement.

  1. Make sure you are using TestNG 7.0.0-beta1 (latest released version as of today)
  2. Within your suite xml file, add a suite level parameter that captures all the state values for which you need the tests to be repeated separating them by ,
  3. Build a org.testng.IAlterSuiteListener implementation that basically splits the suite level parameter into multiple parameters, retries the tests in the suite, clones them and adds the split parameters to each of the tests.

The below sample should show how this would work.

Test class looks like this

package com.rationaleemotions.stackoverflow.qn53803675;

import org.testng.ITestResult;
import org.testng.Reporter;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;

public class SampleTestClass {

  @Test
  @Parameters("state")
  public void testMethodOne(int state) {
    printer(state);
  }

  @Test
  @Parameters("state")
  public void testMethodTwo(int state) {
    printer(state);
  }

  private void printer(int state) {
    ITestResult result = Reporter.getCurrentTestResult();
    String methodname = result.getMethod().getMethodName();
    String testname = result.getTestContext().getName();
    String msg =
        String.format("%s() from <%s> running with state [%d]", methodname, testname, state);
    System.err.println(msg);
  }
}

Here's how the suite altering listener would look like

package com.rationaleemotions.stackoverflow.qn53803675;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.testng.IAlterSuiteListener;
import org.testng.xml.XmlSuite;
import org.testng.xml.XmlTest;

public class SimpleSuiteAlterer implements IAlterSuiteListener {

  @Override
  public void alter(List<XmlSuite> suites) {
    XmlSuite suite = suites.get(0);
    // Fetch the suite level parameter called "states" and split it by comma
    // We will get all the states that we need to run for.
    String[] states = suite.getParameter("states").split(",");
    // We are going to assume that only those <test> tags that begin with "dynamic"
    // in their names will be considered for multiple execution.
    List<XmlTest> dynamictests =
        suite
            .getTests()
            .stream()
            .filter(xmlTest -> xmlTest.getName().startsWith("dynamic"))
            .collect(Collectors.toList());

    List<XmlTest> clonedTests = new ArrayList<>();
    for (XmlTest each : dynamictests) {
      for (int i = 1; i < states.length; i++) {
        XmlTest cloned = new XmlTest(suite);
        cloned.addParameter("state", states[i]);
        cloned.setName(each.getName() + "_cloned");
        cloned.getXmlClasses().addAll(each.getClasses());
        clonedTests.add(cloned);
      }
      each.addParameter("state", states[0]);
    }
    dynamictests.addAll(clonedTests);
  }
}

Here's how the suite xml file looks like

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="53803675_suite" parallel="false" verbose="2">
  <listeners>
    <listener class-name="com.rationaleemotions.stackoverflow.qn53803675.SimpleSuiteAlterer"/>
  </listeners>
  <parameter name="states" value="1,2"/>
  <test name="dynamic-53803675-test">
    <classes>
      <class name="com.rationaleemotions.stackoverflow.qn53803675.SampleTestClass"/>
    </classes>
  </test>
</suite>

Here's how the output looks like

...
... TestNG 7.0.0-beta1 by Cédric Beust ([email protected])
...
testMethodOne() from <dynamic-53803675-test> running with state [1]
testMethodTwo() from <dynamic-53803675-test> running with state [1]
testMethodOne() from <dynamic-53803675-test_cloned> running with state [2]
PASSED: testMethodOne(1)
PASSED: testMethodTwo(1)

===============================================
    dynamic-53803675-test
    Tests run: 2, Failures: 0, Skips: 0
===============================================

testMethodTwo() from <dynamic-53803675-test_cloned> running with state [2]
PASSED: testMethodOne(2)
PASSED: testMethodTwo(2)

===============================================
    dynamic-53803675-test_cloned
    Tests run: 2, Failures: 0, Skips: 0
===============================================

===============================================
53803675_suite
Total tests run: 4, Passes: 4, Failures: 0, Skips: 0
===============================================


Process finished with exit code 0

Upvotes: 1

murali selenium
murali selenium

Reputation: 3927

try like this

//This method will provide data to any test method that declares that its Data Provider
//is named "test1"
@DataProvider(name = "test1")
public Object[][] createData1() {
return new Object[][] {
  { "Cedric", new Integer(36) },
  { "Anne", new Integer(37)},
 };
}

 //This test method declares that its data should be supplied by the Data Provider
 //named "test1"
 @Test(dataProvider = "test1")
public void verifyData1(String n1, Integer n2) {
 System.out.println(n1 + " " + n2);
}

see here http://testng.org/doc/documentation-main.html#parameters-dataproviders

Upvotes: 2

Related Questions