0

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.

Eugene A
  • 330
  • 4
  • 16
  • I think having a test method with a return value is not a good design. Maybe you want to have a look into mocking (e.g. http://mockito.org/)? – LiMuBei Feb 26 '16 at 14:07
  • I thought it might be suboptimal too. These are black box tests, quite isolated from the code. I have complex events happening in test1(), but I only need to assert the status of one of these events in test2(). It will be rather hard to mock everything happening in the system under test, but coupling here looks very natural, because there is nothing else outside of test1() and test2() to change the state of objects (and if there is, it is a defect) and I only need to execute test2() if test1() passed. – Eugene A Feb 26 '16 at 14:15
  • 1
    Seems there is an option in the test annotation called `dependsOnMethods` that might do what you want, see http://www.tutorialspoint.com/testng/testng_dependency_test.htm – LiMuBei Feb 26 '16 at 14:17
  • Thanks, it does enforce sequential execution, but is there a way to pass an object to a test from an upstream test? I'd rather avoid declaring internal objects on a class level. – Eugene A Feb 26 '16 at 14:24

3 Answers3

1

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);
}
djangofan
  • 28,471
  • 61
  • 196
  • 289
0

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());
}
mfulton26
  • 29,956
  • 6
  • 64
  • 88
0

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