0

I have some integration tests which create embedded instances of Kafka and Zookeeper in @BeforeClass.

In @AfterClass those instances are shut down.

Problem is, Kafka / Zookeeper are expensive to shut down, so my tests take a long time to shut down after they have finished running.

Is it possible to write a JUnit test runner which just forcefully shuts down all child threads started by the tests?

Ali
  • 261,656
  • 265
  • 575
  • 769

1 Answers1

0

I don't think you want to implement the custom Runner, because after all Runner will still run per test case. I believe you're looking for a way to run all the tests in a module (probably by the build tool) and yet to have Kafka and Zookeper run only once.

So technically you can't really achieve that with JUnit, at least I'm not aware of any good way to do that, like you know, put some fancy annotation here and there and it will work. There are couple of approaches I think that can help though:

  1. Test Suites. You can create a Test Suit that will contain all the integration test in the module. Then you can put a "@BeforeClass/@AfterClass on the methods of class that runs with a suit runner. In these methods you can start/stop the heavy stuff (Kafka, zookeeper). Here you can find a complete technical example. The drawback of course is that you'll have to maintain the Suite classes.

  2. Assuming you have spawn a jvm for the integration tests module (forking), its possible to apply the following technique:

    • Create a code that will start Kafka / Zookeper and make sure it will execute only once. You can create some common parent for all your tests, and use static boolean isMyHeavyStuffRunning shared state variable at the level of parent.

    • Implement a Shutdown hook and add it to the runtime. When all the tests will be done, the JVM will halt, but right beforehand your listener will be called and you'll be able to shutdown the Kafka/Zookeper.

The example of Shutdown thread hooks.

halfer
  • 19,824
  • 17
  • 99
  • 186
Mark Bramnik
  • 39,963
  • 4
  • 57
  • 97
  • Thanks - Already using `Before/AfterClass`. The problem is, `AfterClass` takes a very long time to gracefully shut down the embedded Kafka/ZK instances, and this happens for each test. Is there a way to shutdown all threads created during before/after test? – Ali Nov 23 '16 at 00:32
  • Please read carefully my answer. Both solutions offered in the answer assume that you won't run the heavy code after each test... Instead you can startup you heavy infra components (ZK, Kafka, etc), run all the tests, and then shutdown infra components. My answer basically explains how you can do that... – Mark Bramnik Nov 23 '16 at 12:03
  • Your first example says to use Suites and for each test class, have a before/afterClass, right? That's the same as what i'm doing now - the afterClass is where the delay occurs as they take a long time to shut down. Your 2nd solution is more promising, but won't the static boolean var's state get lost between each test class? – Ali Nov 24 '16 at 11:18
  • Nope. I mean to implement before/after class methods only at the level of suite. Don't implement these methods on test cases at all. Run only suit... thats the first solution. The 2nd will work as long as you don't fork for each test case... if all tests share the same classloader it should work – Mark Bramnik Nov 24 '16 at 11:25
  • If I created a custom runner, is there no way for the runner to shut down all threads created by the test it ran? – Ali Nov 24 '16 at 11:29
  • Runner manages one test case... its not aware of threads spawn by the test case. So technically runner wont help you here. – Mark Bramnik Nov 24 '16 at 11:31
  • I don't mind kafka being created per test. That doesn't take long. Shutting it down gracefully is what takes long, but if I can somehow just shut down all threads it creates without shutting it down gracefully, that will resolve my issue (and will let my existing tests continue to work without changing everything) – Ali Nov 24 '16 at 11:31
  • But you can declare a class to be @RunWith. In that case, don't the before/after class get sent to the runner? – Ali Nov 24 '16 at 11:32
  • I thought its better to not touch kafka threads between tests at all. Create it first then run all tests in a module and only then shut down kafka gracefully. Once in a module and not per test. I have to admit i'm not familiar with kafka though – Mark Bramnik Nov 24 '16 at 11:37
  • Problem is, if i use suites or the shutdown method, I'll have to modify my existing tests, and/or it won't play nice with regular maven compiles, and/or travis. So the ideal solution would be if I can use a runner or another solution which will either fork a new JVM for each class, run tests of that class, then just shut down the forked jvm. Or shut down all threads started by the class after running its tests. These are throwaway kafka instances so its fine to kill them ruthelessly. – Ali Nov 24 '16 at 11:49