2

Does Spring or the JUnit runner have something that I can use to run code before running ANY tests?

The closest I've found is the @Rule and @ClassRule, which work on a class level.

I have a Docker @ClassRule which hosts an empty database for empty integration testing. With the @ClassRule, it restarts the container every time.

I'd prefer instead to just start it once when starting the tests (regardless if it's all tests or just a single one), runs the tests, then kill the container.

I've searched around, but I haven't found anything other than the class rule. Apologizes if I'm missing something obvious.

samanime
  • 25,408
  • 15
  • 90
  • 139
  • @Before or @BeforeClass doesn`t satisfy your requirement? – Barath Jan 08 '18 at 17:00
  • https://stackoverflow.com/a/12088135/3620458 – Bragolgirith Jan 08 '18 at 17:04
  • @Barath I'm looking for something that runs once per set of tests. So, if I run all tests, I want something that'll only fire once, not once per class (`@BeforeClass`) or once per test (`@Before`) – samanime Jan 08 '18 at 17:13
  • In my case, what I was doing was looking for a way to spin up dockerized databases which I could run tests again. I didn't want to spin up a new one per test or class because it would be WAY too slow. We've used the code in my answer below since I posted it and it works great still. – samanime Sep 19 '19 at 13:56

2 Answers2

2

It appears that Spring and JUnit don't directly have anything to do this. After some more googling, I found a few bits that lead to some inspiration.

Making use of a custom rule extending ExternalResource (from JUnit), I'm kind of bastardizing it, but it does what I want:

public class MyRule extends ExternalResource {
  static private MyRule instance;

  static public MyRule get() {
    if (instance == null) {
      instance = new MyRule();
    }

    return instance;
  }

  private MyRule() {
    // do init stuff

    Runtime.getRuntime().addShutdownHook(new Thread(() -> {
      // do shutdown stuff
    });
  }
}

The basic idea is that the rule is a singleton. In each class that might need it, I'd put an @ClassRule:

 public class MyTest {
   @ClassRule
   private MyRule myRule = MyRule.get();
 }

It'll lazy-initialize itself, which will do all of the setup needed. It'll also register a shutdown hook, which will then handle any after stuff.

With this pattern, it'll run code exactly once before any tests (that need this rule) run, and it'll perform shutdown code only at the very end after all tests have finished.

Note: It purposely doesn't override the before() and after() functions, because those are before and after each class. You could add things there if you wanted to do something in between classes as well.

samanime
  • 25,408
  • 15
  • 90
  • 139
-1

Maybe what you are looking for are those 2 annotations :

@BeforeClass

@Before

@Before runs before each test while @BeforeClass runs only once

You can use it like this :

@Before
public void setUp(){
// start container here
}

You also have equivalent for after test : @After @AfterClass

You will find a great explanation here

Thanks

M. Deinum
  • 115,695
  • 22
  • 220
  • 224
A Le Dref
  • 422
  • 3
  • 7
  • 1
    I need something that runs once per run, not once per class or per test. – samanime Jan 08 '18 at 17:14
  • @samanime then if you use JUnit 5 you have [@BeforeAll](http://junit.org/junit5/docs/current/api/org/junit/jupiter/api/BeforeAll.html) that seems to do the trick ! Example [here](https://howtodoinjava.com/junit-5/before-all-annotation-example/) – A Le Dref Jan 08 '18 at 17:27
  • Unfortunately, even @BeforeAll still seems to be class level. I'm trying to find something that'll trigger just once for an entire run of multiple classes. – samanime Jan 08 '18 at 17:32
  • Then maybe you should make a test suite instead of multiple test classes. I'm don't know much about it but maybe [this answer](https://stackoverflow.com/questions/82949/before-and-after-suite-execution-hook-in-junit-4-x) could help you ? – A Le Dref Jan 08 '18 at 17:36
  • Sorry for the typo : I don't know much – A Le Dref Jan 08 '18 at 17:49
  • Thanks for the though. It's a good idea, but in this case, it'd literally be any test in the entire project (which there are probably 30+ classes with 600+ tests, so that'd be big). – samanime Jan 08 '18 at 18:55