views:

290

answers:

4

I have an abstract basis class, which I use as a basis for my unit tests (TestNG 5.10). In this class I initialize the whole environment for my tests, setting up database mappings, etc. That abstract class has a method with a @BeforeClass annotation which does the initialization. Next thing, I extend that class with specific classes in which I have @Test methods and also @BeforeClass methods. These methods do class-specific initialization of the environment, e.g. put some records into the database.

My question is how I can enforce a specific order of the @BeforeClass annotated methods. I need the ones from the abstract base class to be executed before the ones of the extending class.

Example:

abstract class A {
 @BeforeClass
 doInitialization() {...}
}

class B extends A {
 @BeforeClass
 doSpecificInitialization() {...}

 @Test
 doTests() {...}
}

Expected order:

A.doInitialization
B.doSpecificInitialization
B.doTests

Actual order:

B.doSpecificInitialization // <- crashes, as the basic init is missing
(A.doInitialization        // <---not executed
 B.doTests)                // <-/
+1  A: 

Don't put the @BeforeClass on the abstract class. Call it from each subclass.

abstract class A {
    void doInitialization() {}
}

class B extends A {
    @BeforeClass
    void doSpecificInitialization() {
        super.doInitialization();
    }

    @Test
    void doTests() {}
}

Seems like TestNG has @BeforeClass(dependsOnMethods={"doInitialization"}) - give it a try.

Bozho
That's basically what I wanted to avoid: no need to explicitly call methods of the super (abstract) class. Especially as I also have classes, which inherit from A but don't have an own @BeforeClass method. I'd have to insert one only for that purpose.
DaDaDom
The `dependsOnMethods` workaround did the trick. Although I'd prefer a "superclass first" approach ...
DaDaDom
A: 

According to the JUnit api: "The @BeforeClass methods of superclasses will be run before those the current class."

I tested this, and it seems to work for me...

Fortega
he's using TestNG, not JUnit
Bozho
ah yes, didn't see that...
Fortega
+1  A: 

I just tried your example with 5.11 and I get the @BeforeClass of the base class invoked first.

Can you post your testng.xml file? Maybe you are specifying both A and B there, while only B is necessary.

Feel free to follow up on the testng-users mailing-list and we can take a closer look at your problem.

-- Cedric

Cedric Beust
No .xml for testng defined (explicitly), it's run from Eclipse and Maven.
DaDaDom
How are you running it from Eclipse exactly? Right clicking on class B?
Cedric Beust
A: 

How about having your @BeforeClass method call an empty specificBeforeClass() method that may or may not be overwritten by sub classes like so:

public class AbstractTestClass {
  @BeforeClass
  public void generalBeforeClass() {
    // do stuff
    specificBeforeClass();
  }

  protected void specificBeforeClass() {}
}

public class SpecificTest {
  @Override
  protected void specificBeforeClass() {
    // Do specific stuff
  }

  // Tests
}
Tatome