5

Let say I have a test class called MyTest.

In it I have three tests.

public class MyTest {

AnObject object;

@Before
public void setup(){
  object = new AnObject();
  object.setSomeValue(aValue);
}

@Test
public void testMyFirstMethod(){
    object.setAnotherValue(anotherValue);
    // do some assertion to test that the functionality works
    assertSomething(sometest);
}

@Test
public void testMySecondMethod(){
    AValue val = object.getAnotherValue();
    object.doSomethingElse(val);
    // do some assertion to test that the functionality works
    assertSomething(sometest);
}

Is there any way I can use the value of anotherValue, which is set with its setter in the first test, in the second test. I am using this for testing database functionality. When I create an object in the DB I want to get its GUID so I can use this to do updates and deletes in later test methods, without having to hardcode the GUID and therefore making it irrelevant for future use.

BenMorel
  • 34,448
  • 50
  • 182
  • 322
Ankur
  • 50,282
  • 110
  • 242
  • 312

6 Answers6

5

You are introducing a dependency between two tests. JUnit deliberately does not support dependency between tests, and you can't guarantee the order of execution (except for test classes in a test suite, see my answer to Has JUnit4 begun supporting ordering of test? Is it intentional?). So you really want to have dependencies between two test methods:

  1. you have to use an intermediate static value
  2. as Cedric suggests, use TestNG, which specifically supports dependencies
  3. in this case, you can create a method to create the line, and call it from both methods.

I would personally prefer 3, because:

  1. I get independent tests, and I can run just the second test (in Eclipse or such like)
  2. In my teardown in the class, I can remove the line from the database, the cleanup. This means that whichever test I run, I always start off with the same (known) database state.

However, if your setup is really expensive, you can consider this to be an integration test and just accept the dependency, to save time.

Community
  • 1
  • 1
Matthew Farwell
  • 60,889
  • 18
  • 128
  • 171
3

First off, make sure your @Test 's run in some kind of defined order i.e. @FixMethodOrder(MethodSorters.NAME_ASCENDING) In the example below, I'm assuming that test2 will run after test1 To share a variable between them, use a ThreadLocal (from java.lang). Note that the scope of the ThreadLocal variable is to the thread, so if you are running multiple threads, each will have a copy of 'email' (the static in this case implies that its only global to the thread)

private static ThreadLocal<String> email = new ThreadLocal<String>();
@Test
public void test1 {
    email.set("hchan@apache.org);
}

@Test
public void test2 {
   System.out.println(email.get());
}
Henry Chan
  • 31
  • 1
3

You should use TestNG if you need this (and I agree it's fairly common in integration testing). TestNG uses the same instance to run your tests, so values stored in fields are preserved between tests, which is very useful when your objects are expensive to create (JUnit forces you to use statics to achieve the same effect, which should be avoided).

Cedric Beust
  • 15,480
  • 2
  • 55
  • 55
  • Thanks, I recently moved from TestNG to JUnit (although obviously wasn't an expert) so this will be an easy move. – Ankur Jan 16 '12 at 13:33
2

You should not do that. Tests are supposed to be able to run in random order. If you want to test things that depend on one value in the database, you can do that in the @Before code, so it's not all repeated for each test case.

Eve Freeman
  • 32,467
  • 4
  • 86
  • 101
  • Wes I get what you're saying. But I think this is the one case where that's not true. Because I'd have to put potentially untested functionality into the @Before code. – Ankur Jan 08 '12 at 06:29
  • 2
    Then make a function to call at the start of all of your tests. You don't want to make it so you can't run tests in parallel. – Eve Freeman Jan 08 '12 at 08:56
  • Maintaining state is not mutually exclusive with running your tests in parallel, see how TestNG does it (and my answer). – Cedric Beust Jan 08 '12 at 17:24
  • Thanks for the followup, I like the idea of putting the code in a separate method. – Ankur Jan 16 '12 at 13:38
1

I have found nice solution, just add Before annotation to the previous test!

private static String email = null;
@Before
@Test
public void test1 {
    email = "test@google.com"
}

@Test
public void test2 {
   System.out.println(email);
}
pg7812
  • 21
  • 5
0

If you, like me, googled until here and the answer didn't serve to you, I'll just leave this: Use @BeforeEach

DanielJr
  • 16
  • 2