Search code examples
javajunitjunit-runner

How to write a JUnit runner that runs a @BeforeCategory method before a TestCase in a @Category?


I'm trying to write a specific JUnit Runner, and I did not find good tutorials / examples online.

The requirements are the following :

  • I will have some categorized tests (e.g A.java from category catA, B.java from category catA, C.java from Category catC
  • Each test has a single @BeforeClass method that needs to be run if the test is launched alone
  • When launching all tests from the same category, the @BeforeClass method must only be launched once.
  • Each @Test method from a Junit Test also has @Before and @After methods.

That being said, I looked at the different options available.

I started by creating Test Suites which would represent my test categories, using the provided junit Suite Runner. (@RunWith(Suite.class)) You need to manually provide the Tests in the suite, using @SuiteClasses() which is annoying.

So I looked at the ClasspathSuite Runner, which allows to put all classes from the classpath in every suite, and filter them after with @Category

It also provides a @BeforeSuite annotation that is launched once when the suite is launched.

=> Everything is almost perfect.

  • When a single test is launched, the @BeforeClass from this test is launched
  • When a Test Suite is launched, the correct Tests are launched (thanks to the @Category), the @BeforeSuite is called only once, but the @BeforeClass of every Test is also called, where it should not.

=> All these things led me to think about implementing my own Runner. I tried extending the ClasspathSuite Runner, but it is not designed to do so. I tried extending the stock Suite Runner, but I did not succeed.

Could you help me understand how to implement these requirements in a JUnit Runner?


Solution

  • How about doing it without writing a runner? Instead, write a @BeforeClass method that uses a singleton list that records each before-category method that has been run in the current test run, and that knows how to run all the before-category methods (each probably in its own class). The @BeforeClass method determines its class's @Category, checks the list, and

    • does nothing if that @Category's before-category method has already run, or
    • runs the before-category method and note in the list that that @Category's method has been run.

    Not requiring a custom runner is better because it will work in environments that provide their own runners, such as IDEs and continuous integration servers.