ricb
ricb

Reputation: 1217

TestNG - sharing state between test classes

I have a suite of test classes that I am running via a testng.xml file. This works fine. All tests are run serially, so no parallel-execution hurdles.

My goal now is to take state that was generated by the test methods in one test class (e.g., a customerId primary key value generated by a database insert) and pass it along to another test class, so that the test methods in that second class can take further action based on that shared state (e.g., look up the just-inserted customer using the customerId value from the first class).

It's easy to share state between test methods in a single class, of course, via class member variables, but I don't see how to share it across test classes.

Upvotes: 6

Views: 6852

Answers (5)

Vivek Goel
Vivek Goel

Reputation: 782

ITestContext will work fine if both the test cases are in same test scope. If we have to share data between tests in different test context but same suite then we have to set the data in suite context.

public class SharingDataSuiteLevelISuiteFirstTest {
    
    // Passing ITestContext as a parameter to @Test method to use it. 
    @Test
    public void generateData(ITestContext context)
    {
        String firstName = "Amod";
        // Get the suite
        ISuite suite = context.getSuite();
        // Setting an attribute with name and its value at suite level in stead of test level
        suite.setAttribute("FirstName", firstName);
    }
}

public class SharingDataSuiteLevelISuiteSecondTest {
    
    // Passing ITestContext as a parameter to @Test method to use it. 
    @Test
    public void useData(ITestContext context)
    {
        String lastName = "Mahajan";
        // Retrieving attribute value set in ITestContext
        ISuite suite = context.getSuite();
        String FN = (String) suite.getAttribute("FirstName");
        String fullName = FN +" "+lastName;
        System.out.println("Full Name is : "+fullName);
    }
}

More explanation to the above problem can be found here: http://makeseleniumeasy.com/2020/01/06/testng-tutorials-68-sharing-data-between-tests-in-a-suite-using-isuite-itestcontext/

Upvotes: 0

Sam
Sam

Reputation: 556

As we know from TestNG JavaDoc, ITestContext defines a test context which contains all the information for a given test run. An instance of this context is passed to the test listeners so they can query information about their environment. So we can share generated data from one class in this test with another class in this test.

Producer.java

public List<String> groupIds = ...;
@AfterClass(alwaysRun = true)
public void reserveGroupIds(ITestContext ctx) {
    ctx.setAttribute(GROUPS_ATTR, groupIds);
}

Consumer.java

public List<String> groupIds;
@BeforeClass(alwaysRun = true)
public void fetchGroupIds(ITestContext ctx) {
    groupIds = (List<String>) ctx.getAttribute(Producer.GROUPS_ATTR);
}

mySuite.xml

...
<test>
  <classes>
    <class name= "Producer"/>
    <class name= "Consumer"/>
  </classes>
</test>
...

Upvotes: 0

Ivan Gerasimenko
Ivan Gerasimenko

Reputation: 2428

Another way is to use means of object oriented programming.

Common structure of tests for example:

  • TestBase.java (parent class for all other test classes, has methods like @BeforeTest, @AfterSuite, etc.)
    • RegistrationTests.java (extends TestBase, )
    • ShoppingTests.java (extends TestBase)
    • and WhateverElseTests.java (extends TestBase)

So TestBase has all shared data as static fields e.g. Customer object:

public class TestBase {

    protected static final BrowserManager bw = new BrowserManager();
    protected static Customer customer;

    @BeforeSuite
    public void initBrowser() {
        bw.init();
    }

    @AfterSuite
    public void terminateBrowser() {
        bw.terminate();
    }

}

And access to customer in tests, e.g. ShoppingTests.java:

public class ShoppingTests extends TestBase {

    @Test
    public void doSomethingTest() {

        bw.navigateTo().shoppingPage();

        bw.shoppingPreparationHelper().checkDisplayedName(customer.name);
        ...

N.B.: tests that share objects should go in a strict sequence (first - test that init object, then - test that uses object's data), so use @Test(dependsOnMethods = "someMethodTest"). Otherwise you are in risk of NullPointerException for customer.

P.S.: Object-oriented way has great advantage over ITestContext because you can pass any object(s) from test to test (also between classes), not just string attribute.

Upvotes: 1

Dmitry Glushonkov
Dmitry Glushonkov

Reputation: 325

Really Testng-y way to do this is to set ITestContext attribute with desired value and then get it from other test class.

Set value:

@Test
public void setvaluetest(ITestContext context) {
        String customerId = "GDFg34fDF";
        context.setAttribute("customerId", customerId);
}

Get value:

@Test
public void getvaluetest(ITestContext context) {
        String id = context.getAttribute("customerId");
}

Upvotes: 4

Bob Dalgleish
Bob Dalgleish

Reputation: 8227

Use a factory to create a repository. The repository stores "interesting test state" properties.

  TestRepository tr = TestRepositoryFactory.getInstance();
  ...
  tr.store("test13.PKID", pkid.toString());

and then in your subsequent code, repeat the call to the factory and then get the value:

  String spkid = tr.get("test13.PKID");

Upvotes: 1

Related Questions