36

I want to run a test case multiple times. Is that configurable in the testng.xml? If I add a loop in the test method, then the results of each run will not be affected in the testng report.

Andrejs
  • 10,803
  • 4
  • 43
  • 48
Feixiong Liu
  • 443
  • 1
  • 7
  • 14

8 Answers8

54

You cannot do it from the xml, but in the @Test annotation - you can add a invocationCount attribute with the number of times you want to run it. It would come out as those many tests run in the report.

eg.

@Test(invocationCount = 10)
public void testCount() {..}

You have missed closing curly bracket at the end, so a small correction.

niharika_neo
  • 8,441
  • 1
  • 19
  • 31
  • That's too bad because being able to configure in XML rather than code is very important for some use cases. For example: I have a functional test case purchaseXYZ(). In my functional test suite I just want to run it a single time to see if anything is broken. In my performance test suite I want to run it 100 times to get average latency. Thus I need to be able to specify number of invocations from XML, not hardcoded in the code. – Thomas Nguyen Aug 27 '15 at 19:03
  • 1
    Why not just make a second test then - one for functional and one for unit testing? – fIwJlxSzApHEZIl May 17 '17 at 00:29
  • @anon58192932 While I can see that would work, it seems more like a workaround than a solution. – John Chesshir Jun 23 '17 at 14:04
  • @JohnChesshir the best solution is often the workaround that's easiest to implement since there's always a bigger problem to solve it seems. – fIwJlxSzApHEZIl Jun 23 '17 at 17:05
  • @anon58192932 True. I'm just a stickler for details, though, as you can see my own answer. – John Chesshir Jun 27 '17 at 17:25
9

TestNg has one method. You can use this method and run your test case multiple times:

@Test(invocationCount = 100)

public void testCount() {

}
Andrejs
  • 10,803
  • 4
  • 43
  • 48
Vipin Pandey
  • 659
  • 8
  • 17
  • 1
    Can you please [edit] your answer and clarify what you mean? As it is right now, I can't understand whether you are giving a new answer or commenting on [niharika_neo's answer](http://stackoverflow.com/a/26134824/3982001). If you want to ask something about it you should do it in a new question, not here. This is a Q&A site, not a forum. Thank you! – Fabio says Reinstate Monica Jan 31 '17 at 14:00
7

None of the answers so far really give the user the ability to up the invocation count from the testng file, which is what was asked for. This solution piggybacks off of gaurav25's DataProvider solution.

class TestClass() {
    int invocations;

    @Parameters({ "invocationCount" })
    @BeginClass
    void BeginClass( @Optional("1") String invocationCount) {
        this.invocations = Ingeter.parse(invocationCount)
    }

    // It will return a 2D array of size 3x1
    @DataProvider(name="URLprovider")
    private Object[][] getURLs() {
        ArrayList<Object []> obj = new ArrayList<>(3 * this.invocations);

        for(int iCount = 0; iCount < this.invocations; ++iCount) {
            list.add( new Object[] {"https://www.google.co.in/"} );
            list.add( new Object[] {"http://www.gmail.com/"} );
            list.add( new Object[] {"http://stackoverflow.com/"} );
        }

        return list.toArray();
    }

    /* Since Data provider for this test method returns 2D array of size
     (3*invocations)x1, this test method will run 3*invocations 
     times **automatically** with 1 parameter every time. */
    @Test(dataProvider="URLprovider")
    private void notePrice(String url) {
        driver.get(url);
        System.out.println(driver.getTitle());  
    }
}

Now you can alter how many test sets get run through the test function with this testng.xml file:

<suite name="ESFService" verbose="1" parallel="methods" thread-count="1" data-provider-thread-count="10" >
    <test name="Basic">
        <classes>
            <class name="TestClass">
                <parameter name="invocationCount" value="5"/>
            </class>
        </classes>
    </test>
</suite>
John Chesshir
  • 590
  • 5
  • 20
  • On this code my pet-peeve is using the same variable name for String invocationCount and int invocationCount. This always leads to confusion and possible bugs. And your method getURls() list is not defined. – JPM Mar 29 '21 at 21:52
  • @JPM Point taken on invocationCount. I have changed the member variable and all the places that use it to just "invocations". Regarding getURLs(), the method is clearly defined. I think you probably meant to say it is never "used". Going with that assumption, although it is true that the method is never directly called, it is used via the DataProvider annotation assigned to it. Notice that annotation sets the attribute "name" to "URLprovider". This value is then referenced by the Test annotation on the notePrice function by setting its dataProvider attribute to the same value. – John Chesshir Apr 28 '21 at 21:04
2

I know pretty late to the party but if your aim is to achieve report for each run then you can try TestNG Listener IAnnotationTransformer

code Snippet

public class Count implements IAnnotationTransformer {

    @Override
    public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {
        // TODO Auto-generated method stub
        annotation.setInvocationCount(numberOfTimesTOExecute);
    }

xml snippet

<listeners>
<listener class-name="multiple.Count"></listener>

Mohammad Faisal
  • 573
  • 5
  • 13
  • This seems pretty good. But can you get the numberOftimesTOExecute variable populated from the testng.xml file? – John Chesshir Jun 23 '17 at 13:54
  • It's possible to create a "service loader". see answer to this question: https://stackoverflow.com/questions/45593426/testng-set-invocationcount-globally – Andrejs Aug 23 '17 at 20:42
2

You can add multiple tests in testngSuite and execute. Under all tests the classes names should be same inorder to execute same script multiple number of times.

Sreenivas
  • 21
  • 1
  • 1
    This whole question seems to be old, but just in case someone is still looking (I was) THIS is the answer. It is ALL in the XML. Just create multiple – Rob G Jun 24 '22 at 02:57
1

You cannot do it from the xml, but it can be achieved by using @DataProvider annotation in TestNG.

Here is a sample code:

/* Since Data provider for this test method returns 2D array of size 3x1, 
this test method will run 3 times **automatically** with 1 parameter every time. */
@Test(dataProvider="URLprovider")
private void notePrice(String url) {
    driver.get(url);
    System.out.println(driver.getTitle());  
}

// It will return a 2D array of size 3x1
@DataProvider(name="URLprovider")
private Object[][] getURLs() {
  return new Object[][] {
    {"https://www.google.co.in/"},
    {"http://www.gmail.com/"},
    {"http://stackoverflow.com/"}
  };
}
gaurav25
  • 66
  • 4
1
public class ProcessTest implements ITest {


    protected ProcessData processData;

    @Test
    public void executeServiceTest() {
        System.out.println(this.processData.toString());
    }

    @Factory(dataProvider = "processDataList")
    public RiskServiceTest(ProcessData processData) {
        this.processData = processData;
    }

    @DataProvider(name = "processDataList", parallel=true)
    public static Object[] getProcessDataList() {

        Object[] serviceProcessDataList = new Object[10];

    for(int i=0; i<=serviceProcessDataList.length; i++){
        ProcessData processData = new ProcessData();
        serviceProcessDataList[i] = processData
    }


        return serviceProcessDataList;
    }

    @Override
    public String getTestName() {

        return this.processData.getName();
    }
}

By using @Factory and @DataProvider annotation of TestNG you can execute same test-case multiple times with different data.

Radadiya Nikunj
  • 988
  • 11
  • 10
0

If you don't mind using Sprint, you can create this class:

package somePackage;

import org.junit.Ignore;
import org.junit.runner.Description;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;
import org.springframework.test.annotation.Repeat;

public class ExtendedRunner extends BlockJUnit4ClassRunner {

    public ExtendedRunner(Class<?> klass) throws InitializationError {
        super(klass);
    }

    @Override
    protected Description describeChild(FrameworkMethod method) {
        if (method.getAnnotation(Repeat.class) != null
                && method.getAnnotation(Ignore.class) == null) {
            return describeRepeatTest(method);
        }
        return super.describeChild(method);
    }

    private Description describeRepeatTest(FrameworkMethod method) {
        int times = method.getAnnotation(Repeat.class).value();

        Description description = Description.createSuiteDescription(
            testName(method) + " [" + times + " times]",
            method.getAnnotations());

        for (int i = 1; i <= times; i++) {
            description.addChild(Description.createTestDescription(
                getTestClass().getJavaClass(), "[" + i + "] "
                        + testName(method)));
        }
        return description;
    }

    @Override
    protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
        Description description = describeChild(method);

        if (method.getAnnotation(Repeat.class) != null
                && method.getAnnotation(Ignore.class) == null) {
            runRepeatedly(methodBlock(method), description, notifier);
        }
        super.runChild(method, notifier);
    }

    private void runRepeatedly(Statement statement, Description description,
            RunNotifier notifier) {
        for (Description desc : description.getChildren()) {
            runLeaf(statement, desc, notifier);
        }
    }

}

Then in the actual test:

package somePackage;

import *.ExtendedRunner;

import org.junit.Ignore;
import org.junit.runner.RunWith;
import org.springframework.test.annotation.Repeat;

@Ignore
@RunWith(ExtendedRunner.class)
public class RepeatedTest{
    @Repeat(value N)
    public void testToBeRepeated() {

    }
}

Where N is the number of times you want the test to repeat.

nzsquall
  • 395
  • 1
  • 10
  • 27
  • i am using testng and data provider. what should I do? now I manipulate the size of ojects array. do you think it is a good idea? – Feixiong Liu Oct 15 '14 at 16:40
  • I think you mean "If you do not mind using **Spring**...." Also note, this is a question about TestNG, not JUnit. – John Chesshir Jun 23 '17 at 13:56