Eugene A
Eugene A

Reputation: 330

Can TestNG tests serve as DataProviders?

I have pairs of tests in my project which I would like to run sequentially in separate methods. Normally I would use a DataProvider to generate the input for the test:

@DataProvider
public Object[][] getUsers() {
    // generate input for test2();
}

@Test(dataProvider = "getUsers")
public void test2(User user) {
    assertSomething(user);
}

but here I need both of these methods to act like tests as I have test logic, which does not belong to data providers.

So I would like something like this:

@Test
public Object test1() {
    User user = createUser();
    assertSomething(user);

    return user.getProperty();
}

@Test // depends on test1 - I do not want to execute this test if test1 fails.
public void test2(Object userProperty) {
    assertSomethingElse(userProperty);
}

I could in fact put the logic from test1 to test2 to achieve what I want, but I wondered if there are more intelligent ways to do it.

Upvotes: 0

Views: 130

Answers (3)

djangofan
djangofan

Reputation: 29669

Yes, there is a way. Something like this is what you want I think. Unlike JUnit, TestNG allows you to hook in before the test method runs and access arguments to your test method, sorta like you could do with AOP:

@DataProvider
public Object[][] getUsers() {
    int[][] multi = new int[][]{
       { 0, new User("Tom") },
       { 0, new User("Sally") }
    };
    return multi;
}

@BeforeMethod
public void setupBeforeEachTest(Object[] args) {
    User x = (User)args[1];
    x.modify();
}

@Test(dataProvider = "getUsers")
public void test1(User user) {
    assertSomething(user);
}

@Test(dataProvider = "getUsers")
public void test2(User user) {
    assertSomethingElse(user);
}

Upvotes: 1

Surbhi Sharma
Surbhi Sharma

Reputation: 119

Here is a solution that will work irrespective of wether you run other suites in parallel .The dependsOnMethods parameter will ensure that test2 runs after test 1 passes.The idea is to implement a factory:

Your test methods will look something like this:

@Test
public void test1(ITestContext context) {
    User objUser = Factory.getUser(context.getName());
    assertSomething(objUser);
}

@Test(dependsOnMethods = "test1")
public void test2(ITestContext context) {    assertSomethingElse(Factory.getUser(context.getName()).getProperty());
}

Factory class will be something like:

public class Factory
{
static Map<testName,User> mainMap;

//This method returns User object to a test based on the test name.
public static User getUser(String testName)
{
if (mainMap == null)
{
    mainMap = new HashTable<testName,User>();
    mainMap.put(testName,new User());
}
if(!mainMap.contains(testName))
{
    mainMap.put(testName,new User());
}

return mainMap.get(testName);
}
}

For more info on the theory behind sharing objects between methods /threads using factory refer the following: http://singinginthesunlight.blogspot.in/2016/02/testng-parallelism-kiss-of-death-or.html

Upvotes: 0

mfulton26
mfulton26

Reputation: 31214

What you are asking for is a stateful test class which is not something that TestNG has any specific support for (e.g. passing data from one test to another). As such, you will need to track the state of things yourself.

If you're not worried about parallelism then a class member field works fine:

private User user;

@Test
public void test1() {
    user = createUser();
    assertSomething(user);
}

@Test(dependsOnMethods = "test1")
public void test2() {
    assertSomethingElse(user.getProperty());
}

If you do want to be able to run multiple instances of the test class in parallel then you'll need to use something like a ThreadLocal<T>:

private static final ThreadLocal<User> USERS = new InheritableThreadLocal<>();

@Test
public void test1() {
    USERS.set(createUser());
    assertSomething(user);
}

@Test(dependsOnMethods = "test1")
public void test2() {
    assertSomethingElse(USERS.get().getProperty());
}

Upvotes: 0

Related Questions