Pregunta

I have what amounts to a lightweight test framework written as a JUnit Abstract test. What I would like to do is have the implementing subclasses each define their custom test class setup. My plan was to have the abstract superclass define an @BeforeClass method that calls into an abstract setup method that each subclass would be forced to define, but this fails as the @BeforeClass methods must be static and static methods cannot be made abstract nor can they call instance methods.

I could just assume that subclasses will do the setup by including what's required in the documentation or by throwing an IllegalStateException, but I'd really like to be able to enforce this at an interface level for a number of reasons. Can anyone think of a work around for this?

By the way, I had the same issue with making these tests parameterized (subclasses define the parameters, but @Parameters annotated methods must be static). I got around this by running with the 3rd party JUnitParams runner which allows method level parameters. Check it out here: https://github.com/Pragmatists/JUnitParams

¿Fue útil?

Solución

One option is to have subclasses implement a, say, static doSetupOnce() method, and find and invoke that method reflectively from the base class @BeforeClass method. Since this needs to be a static method, its existence can only be enforced at runtime.

Another approach would be to have an abstract doSetupOnce instance method in the base class which gets invoked the first time the parent's @Before method gets invoked. This enforces the issue at compile time, but then implementors will have to be careful not to access instance fields from this method (since this is probably not what they want).

In general (and without knowing the details of your situation), I'm not very fond of either of these approaches, and would rather leave it up to implementors to declare a @BeforeClass method if needed. Locking them up in a rigid base class scheme can cause more problems than it solves. Also consider the use of JUnit rules, which often are a better choice than base classes (e.g. because they are composable). Of course you can also combine the two approaches, relying mainly on JUnit rules and additionally offering some base classes with predefined rules for convenience.

Otros consejos

For your main question, why not make your parent class abstract and use the @Before annotation instead of @BeforeClass ? For example:

public abstract class TestParent {
   @Before
   public void setup() {
     doSetup();
   }

   protected abstract void doSetup();

   // other stuff...
}

public class RealTest extends TestParent {
    protected void doSetup() {
      // custom setup
    }

    // custom tests...
}

This will force the subclasses to redefine the doSetup() method without using static methods.

This may be out of scope or overkill, but I think it's worth mentioning since they're not that different. So I'm taking a leap of faith and suggest that you could try TestNG because methods annotated with @BeforeClass do not have to be static, nor do those annotated with @Parameters.

You can read about the differences between the 2 frameworks here and it looks like they also have support for migrating JUnit tests to TestNG

I don't think it is possible to do this in a clean OO way. Not only is @BeforeClass a static method, but JUnit will call the parent's @BeforeClass before the child's @BeforeClass.

Anyway you try to do this must necessarily expose the parent class's internal static state so a child class can set the parent's fields, breaking encapsulation.

I think the best way is to to use @Before, but also have a static flag that sets if the method has been called before, that way at least you can short circuit and only do the initialization for the first call...

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top