30

When using this approach below, by setting up the jUnit with Suites. We got the problem when all @BeforeClass in every Testclass will be executed before any tests starts to execute. (For each n TestClass file the @BeforeClass runs, then after they have execute, it started to execute the first MyTest.class files @Test)

This will cause that we allocate up much resources and memory. My thoughts was that it must be wrong, shouldn't each @BeforeClass run only before the actual testclass is executed, not when the Suite is started?

@RunWith(Suite.class)
@Suite.SuiteClasses({ MyTests.class, Mytests2.class, n1, n2, n })
public class AllTests {
    // empty
}


public class MyTests {  // no extends here
    @BeforeClass
    public static void setUpOnce() throws InterruptedException {
        ...
    @Test
        ...

public class MyTests2 {  // no extends here
    @BeforeClass
    public static void setUpOnce() throws InterruptedException {
        ...
    @Test
        ...
skaffman
  • 398,947
  • 96
  • 818
  • 769
Andreas Mattisson
  • 1,051
  • 2
  • 19
  • 39
  • Are they executed before each classes' tests, or are all executed only before the first (but then the second is run without running all @BeforeClass again)? The latter does seem OK as the @BeforeClass is run before the @Test methods in that test. The amount of memory would not change I suppose, unless you clean up after each class' tests (and these are also only happening after the entire suite is completed). – Fried Hoeben Dec 17 '09 at 12:53
  • 1
    What I get right now is that every @BeforeClass is run first. @BeforeClass (Mytests) @BeforeClass (Mytests2) @Test (MyTests) @Test (MyTests2) At my point of view, this is not correct. Correct me if I'm wrong, but something must be setup wrong to cause this issue. – Andreas Mattisson Dec 17 '09 at 13:59

3 Answers3

51

Write a @BeforeClass method in the AllTests class which will be executed when the suite is started.

public class MyTests1 { 
    @BeforeClass
    public static void beforeClass() {
        System.out.println("MyTests1.beforeClass");
    }

    @Before
    public void before() {
        System.out.println("MyTests1.before");
    }

    @AfterClass
    public static void afterClass() {
        System.out.println("MyTests1.AfterClass");
    }

    @After
    public void after() {
        System.out.println("MyTests1.after");
    }

    @Test
    public void test1() {
        System.out.println("MyTests1.test1");
    }

    @Test
    public void test2() {
        System.out.println("MyTests1.test2");
    }
}



public class MyTests2 { 
    @BeforeClass
    public static void beforeClass() {
        System.out.println("MyTests2.beforeClass");
    }

    @Before
    public void before() {
        System.out.println("MyTests2.before");
    }

    @AfterClass
    public static void afterClass() {
        System.out.println("MyTests2.AfterClass");
    }

    @After
    public void after() {
        System.out.println("MyTests2.after");
    }

    @Test
    public void test1() {
        System.out.println("MyTests2.test1");
    }

    @Test
    public void test2() {
        System.out.println("MyTests2.test2");
    }
}




@RunWith(Suite.class)
@Suite.SuiteClasses( { MyTests1.class, MyTests2.class })
public class AllTests {

    @BeforeClass
    public static void beforeClass() {
        System.out.println("AllTests.beforeClass");
    }

    @Before
    public void before() {
        System.out.println("AllTests.before");
    }

    @AfterClass
    public static void afterClass() {
        System.out.println("AllTests.AfterClass");
    }

    @After
    public void after() {
        System.out.println("AllTests.after");
    }

    @Test
    public void test1() {
        System.out.println("AllTests.test1");
    }

    @Test
    public void test2() {
        System.out.println("AllTests.test2");
    }
    
}

Output:

AllTests.beforeClass
MyTests1.beforeClass
MyTests1.before
MyTests1.test1
MyTests1.after
MyTests1.before
MyTests1.test2
MyTests1.after
MyTests1.AfterClass
MyTests2.beforeClass
MyTests2.before
MyTests2.test1
MyTests2.after
MyTests2.before
MyTests2.test2
MyTests2.after
MyTests2.AfterClass
AllTests.AfterClass
nayakam
  • 4,149
  • 7
  • 42
  • 62
1

I'm not too familiar with @RunWith in JUnit, so I may have done something wrong, but I can't seem to replicate the behaviour you describe. With the class:

@RunWith(Suite.class)
@Suite.SuiteClasses( { FirstTest.class, SecondTest.class, ThirdTest.class })
public class AllTests {
    // empty
}

And FirstTest.java looking like this:

public class FirstTest {
    @BeforeClass
    public static void doBeforeClass() {
         System.out.println("Running @BeforeClass for FirstTest");
    }

    @Test
    public void doTest() {
        System.out.println("Running @Test in " + getClass().getName());
    }
}

... with SecondTest.java and ThirdTest.java pretty much the same. I get the test output:

Running @BeforeClass for FirstTest
Running @Test in FirstTest
Running @BeforeClass for SecondTest
Running @Test in SecondTest
Running @BeforeClass for ThirdTest
Running @Test in ThirdTest

This is with JUnit 4.5.0 (default JUnit in Eclipse 3.5.1) on Sun's JDK 1.6.0_12. Can you spot any difference in my example from yours? Perhaps a different JDK/JVM? I don't know enough about the internals of JUnit to know if these can be a factor.

Grundlefleck
  • 124,925
  • 25
  • 94
  • 111
  • As you describe, is what I was supposed to get also. But I get a bunch of @BeforeClass first, then I see the first @Test, @Test and so on. Using Sun's JDK 1.6.0_17, Eclipse 3.5, but then our Function tests are executed we are using ant, running maven. Could some of this affect the results? If I set it up in Eclipse and run it it works, it seems that this issue is somewhat in ant or maven. – Andreas Mattisson Dec 17 '09 at 15:39
  • Sorry, really can't help you with running JUnit in ant or maven. Though I did export build.xml for the example I used, and ran it with the tests target, and got the behaviour you're looking for, so I doubt it's anything wrong with the JUnit ant task. *puzzled shrug* – Grundlefleck Dec 17 '09 at 17:05
-4

I think, @BeforeClass executes at instanciation.

nfechner
  • 17,295
  • 7
  • 45
  • 64
  • It doesn't. "Annotating a public static void no-arg method with @BeforeClass causes it to be run once before any of the test methods in the class. The @BeforeClass methods of superclasses will be run before those the current class." (Source: JUnit documentation) – Jorn Dec 17 '09 at 13:30
  • Just will add some additional information for those having problem with the memory. JUnit will save all states when running, and will therefor also save all the static variables until all the JUnit tests has executed. This was also a major problem since we are running between 1000-6000 JUnit tests. This because it need it to display the result at the end. – Andreas Mattisson Nov 20 '10 at 16:57