100

I have an abstract base class, which I use as a base for my unit tests (TestNG 5.10). In this class, I initialize the whole environment for my tests, setting up database mappings, etc. This abstract class has a method with a @BeforeClass annotation which does the initialization.

Next, 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).

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 base init is missing
(A.doInitialization        // <---not executed
 B.doTests)                // <-/
Nathan
  • 8,093
  • 8
  • 50
  • 76
Dominik Sandjaja
  • 6,326
  • 6
  • 52
  • 77

16 Answers16

126

edit: Answer below is for JUnit, but I will leave it here anyway, because it could be helpful.

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.

However, as @Odys mentions below, for JUnit you need to have the two methods named differently though as doing otherwise will result in only the subclass method being run because the parent will be shadowed.

Fortega
  • 19,463
  • 14
  • 75
  • 113
  • 61
    Even though the original question was for TestNG, I arrived here after googling for JUnit and your answer helped - thanks! – teabot Jan 28 '11 at 12:28
  • 13
    for JUnit you **need** to have the two methods named differently though as doing otherwise will result in only the subclass method being run because the parent will be shadowed. – Odys Dec 30 '16 at 18:01
  • 3
    @Odys, thank you very much for mentioning this. I was struggling to figure out why the "setup" method in my subclass was running while the one in its superclass was not. You just saved me a ton of aggravation! – Tom Catullo Aug 17 '17 at 17:24
  • You made my day. Thanks! – raiks Feb 28 '20 at 16:54
53

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
  • 588,226
  • 146
  • 1,060
  • 1,140
  • 12
    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. – Dominik Sandjaja Jan 25 '10 at 14:25
  • 6
    The `dependsOnMethods` workaround did the trick. Although I'd prefer a "superclass first" approach ... – Dominik Sandjaja Jan 25 '10 at 14:42
  • 1
    To use "dependsOnMethod" shouldn't "doInitialization" be anotated with "@Test"? That is a problem since technically it is not a test by itself... – N3da Oct 10 '14 at 00:24
  • @BeforeClass should annotate a static method – Fabrizio Stellato Feb 21 '19 at 13:56
7

I added public to the abstract class and TestNG (6.0.1) executed the doInitialization() before doTests. TestNG does not execute doInitialization() if I remove public from class A.

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

class B extends A {    
 @Test
 doTests() {...}
}
Nathan
  • 8,093
  • 8
  • 50
  • 76
Paul
  • 71
  • 1
  • 1
  • 1
    That is true, but irrelevant. This does not work when class `B` *also* has a `@BeforeClass`-annotated method, as in the OP's case. – jpaugh Dec 24 '15 at 17:31
  • 1
    I did the same. It seems order of inheritance is missed if base method is private. Thanks! – Manu Jun 02 '16 at 10:07
6

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
  • 15,480
  • 2
  • 55
  • 55
4

I've just gone through this and found one more way to achieve this. Just use alwaysRun on @BeforeClass or @BeforeMethod in the abstract class, works as you would expect.

public class AbstractTestClass {
    @BeforeClass(alwaysRun = true)
    public void generalBeforeClass() {
        // do stuff
        specificBeforeClass();
    }
}
Konrad Garus
  • 53,145
  • 43
  • 157
  • 230
3

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

But be careful not to name both methods with the same name. Since in this case the parent method will be hidden by child parent. Source.

Anatolii Stepaniuk
  • 2,585
  • 1
  • 18
  • 24
2

When I run from: JUnitCore.runClasses(TestClass.class); It will execute the parent properly, before the child (You do not need super.SetUpBeforeClass();) If you run it from Eclipse: For some reason it fails to run the base class. The work around: Call the base class explicitely: (BaseTest.setUpBeforeClass();) You may want to have a flag in the base class in case you run it from an application, to determine if it is already setup or not. So it only runs once if you run it via both possible methods (such as from eclipse for personal testing, and through ANT for a build release).

This appears to be a bug with Eclipse, or at least unexpected results..

Mark Hall
  • 53,938
  • 9
  • 94
  • 111
Steve
  • 29
  • 3
1

dependsOnMethod can be used.

e.g. in case of Spring (AbstractTestNGSpringContextTests)

@BeforeClass(alwaysRun = true, dependsOnMethods = "springTestContextPrepareTestInstance")
Sandeep Jindal
  • 14,510
  • 18
  • 83
  • 121
1

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
  • 27
  • 1
1

Check your import statement. It should be

import org.testng.annotations.BeforeClass;

not

import org.junit.BeforeClass;

nishantrevo
  • 114
  • 2
  • 4
1

This works for me --

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

class B extends A {
    @Override
    @BeforeClass
    doInitialization() { 

       //do class specific init

    }   

    @Test
    doTests() {...}
}
srikar
  • 11
  • 1
0

Why don't you try to create an abstract method doSpecialInit() in your super class, called from your BeforeClass annotated method in superclass.

So developpers inheriting your class is forced to implement this method.

Ludo
  • 1
  • To be honest, even the logic may have changed within the last 3 1/2 years since I asked this question ... ;-) So yes, maybe this was an idea, maybe it didn't work - I honestly don't remember. – Dominik Sandjaja Sep 05 '13 at 18:22
0

There is another easy solution here.

My particular situation is that I need to inject mock services from "BeforeClass" in the subclass before "BeforeClass" in the superclass is executed.

To do this - simply use a @ClassRule in the subclass.

For example:

@ClassRule
public static ExternalResource mocksInjector = new ExternalResource() {
    @Override
    protected void before() {
        // inject my mock services here
        // Note: this is executed before the parent class @BeforeClass
    }
};

I hope this helps. This can effectively execute static setup in "reverse" order.

vikingsteve
  • 38,481
  • 23
  • 112
  • 156
0

I've faced a similar issue today, the only difference was a Base class was not abstract

Here's my case

public class A {
    @BeforeClass
    private void doInitialization() {...}
}

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

    @Test
    public void doTests() {...}
}

It occurred that a @BeforeClass method from class A was never executed.

  • A.doInitialization() -> THIS WAS NEVER EXECUTED silently
  • B.doSpecificInitialization()
  • B.doTests()

Playing with privacy modifiers I found that TestNG will not execute a @BeforeClass annotated method from inherited class if a method is not visible from a class-inheritor

So this will work:

public class A {
    @BeforeClass
    private void doInitialization() {...}
}

public class B extends A {
    @BeforeClass
    //Here a privacy modifier matters -> please make sure your method is public or protected so it will be visible for ancestors
    protected void doSpecificInitialization() {...}

    @Test
    public void doTests() {...}
}

As a result following happens:

  • A.doInitialization()
  • B.doSpecificInitialization()
  • B.doTests()
rodikno
  • 91
  • 1
  • 4
-1

In my case (JUnit) I have the same methods called setup() in the base class and the derived class. In this case only the derived class's method is called, and I have it call the base class method.

Mike Sokolov
  • 6,914
  • 2
  • 23
  • 31
-2

A better and cleaner way to achieve this using inheritance may be as following -

abstract class A {

    @BeforeClass
    void doInitialization() {}
}

class B extends A {

    @Override
    @BeforeClass
    void doInitialization() {
        super.doInitialization();
    }

    @Test
    void doTests() {}
}
kushal
  • 43
  • 1
  • 6
  • 1
    If you need the method in Parent class to be executed first you just need to name the method in Child class differently from the Parent's (because if they have the same signature then the polymorphism come's in action). I believe it is a cleaner way. – Anatolii Stepaniuk Aug 04 '16 at 12:35