skatkov
skatkov

Reputation: 133

execute some code before any junit test will run

I have a lot of unit tests files that basically execute the same @BeforeClass.

They start jetty web server, add some system properties.

So I'm wondering, is it possible to execute this only once, before unit test will be run?

Upvotes: 7

Views: 3280

Answers (4)

Mauricio Morales
Mauricio Morales

Reputation: 1018

In addition to @Matt's answer about creating your own Runner (which I thought was the best approach) (see the answer here), I also created an additional JUnit test that validates that all of my tests use my Runner (in case one of my developers forgets):

PS: Note this depends on OpenPOJO.

@Test
public void ensureAllTestsUseEdgeRunner() {
    for (PojoClass pojoClass : PojoClassFactory.getPojoClassesRecursively("your.base.package", null)) {
        boolean hasTests = false;
        for (PojoMethod pojoMethod : pojoClass.getPojoMethods()) {
            if (hasTests = pojoMethod.getAnnotation(Test.class) != null) {
                break;
            }
            if (hasTests = pojoMethod.getAnnotation(BeforeClass.class) != null) {
                break;
            }
            if (hasTests = pojoMethod.getAnnotation(Before.class) != null) {
                break;
            }
            if (hasTests = pojoMethod.getAnnotation(AfterClass.class) != null) {
                break;
            }
            if (hasTests = pojoMethod.getAnnotation(After.class) != null) {
                break;
            }
        }
        if (hasTests) {
            PojoClass superClass = pojoClass;
            boolean hasRunWith = false;
            while (superClass != null) {
                // ensure it has the RunWith(EdgeJUnitRunner.class) annotation
                RunWith runWithAnnotation = superClass.getAnnotation(RunWith.class);
                if (runWithAnnotation != null && runWithAnnotation.value() == EdgeJUnitRunner.class) {
                    hasRunWith = true;
                    break;
                }
                superClass = superClass.getSuperClass();
            }

            if (!hasRunWith) {
                throw new RuntimeException(pojoClass.getClazz().getName() + " should be annotated with @RunWith(EdgeRunner.class)");
            }
        }
    }
}

Upvotes: 1

Matt
Matt

Reputation: 17649

You could use the @RunWith annotation:

@RunWith(JettyRunner.class)
public class MyAwesomeTest {
    @Test
    //...
}

And implement a new Runner

public class JettyRunner extends BlockJUnit4ClassRunner {
    private static boolean initialized = false;

    public JettyRunner(Class<?> klass) throws InitializationError {
        super(klass);

        synchronized (JettyRunner.class) {
            if (!initialized) {
                System.out.println("Let's run jetty...");
                initialized = true;
            }
        }
    }
}

I'm not sure if the synchronized block is really needed, just threw it in for good measure...

Upvotes: 10

Tom Anderson
Tom Anderson

Reputation: 47243

Do you run the test classes from a suite? A @BeforeClass on the suite class will run once, before any tests run.

Upvotes: 0

asenovm
asenovm

Reputation: 6517

Maybe using a static initializer will do? Although it's not a very good idea to initialize some fields only once when running unit tests since some of the tests may drive the fields to an illegal state which will impede the running of the other tests.

Upvotes: 1

Related Questions