29

JUnit's @BeforeClass annotation must be declared static if you want it to run once before all the @Test methods. However, this cannot be used with dependency injection.

I want to clean up a database that I @Autowire with Spring Boot, once before I run my JUnit tests. I cannot @Autowire static fields so I need to think of a work around. Any ideas?

kryger
  • 12,906
  • 8
  • 44
  • 65
Kingamere
  • 9,496
  • 23
  • 71
  • 110

5 Answers5

52

Just use @Before (instead of @BeforeClass) (or Spring's @BeforeTransaction (depending on how you initialize the database)). This annotation must been attached to an nonstatic public method.

Of course: @Before run before EACH test case method (not like @BeforeClass that runs only once.) But if you want to run it exactly once, then use an static marker field.

private static boolean initialized = false;
...
@Before
public void initializeDB() { 
   if (!initialized) {
       ... //your db initialization
       initialized = true;
   }
}
---
Steve Chambers
  • 37,270
  • 24
  • 156
  • 208
Ralph
  • 118,862
  • 56
  • 287
  • 383
  • that's what i do when i have to use JUnit. But I prefer to use TestNG which has all annotations available on non-static methods : in your case with TestNG, @BeforeClass would be defined on a non-static methods, and is would be executed once before all the test methods inside that class. – Gauthier Peel Aug 29 '16 at 13:52
  • Is there a workaround for `@AfterClass`? I want to remove all data inserted in the database because I'm using an external database. – LunaticJape May 14 '19 at 15:00
  • 2
    @LunaticJape: my workarround is to use the `@After` Method to pass an instance (`@Autowired` field value) to an static field, and then use this field in the `@AfterClass` Method. – Ralph May 19 '19 at 06:23
  • @LunaticJape see https://stackoverflow.com/questions/37083647/junit-afterclass-non-static – AsfK Jul 16 '20 at 17:20
5

For JUnit5: Test Execution Order and @TestInstance(Lifecycle.PER_CLASS)

Kotlin example:

@ExtendWith(SpringExtension::class)
@TestInstance(PER_CLASS)
class BeforeInstanceTests {

    private var initialized: String = ""
    private val callList: MutableList<String> = ArrayList()

    @BeforeAll
    fun beforeAllNonStatic() {
        initialized = "initialized"
        assertEquals(0, callList.size)
    }

    @Test
    fun test1() {
        assertEquals("initialized", initialized)
        callList.add("test1")
    }

    @Test
    fun test2() {
        assertEquals("initialized", initialized)
        callList.add("test2")
    }

    @Test
    fun test3() {
        assertEquals("initialized", initialized)
        callList.add("test3")
    }

    @AfterAll
    fun afterAllNonStatic() {
        assertEquals("initialized", initialized)
        assertEquals(3, callList.size)
        assertTrue(callList.contains("test1"))
        assertTrue(callList.contains("test2"))
        assertTrue(callList.contains("test3"))

        callList.clear()
        initialized = ""
    }
}
radistao
  • 14,889
  • 11
  • 66
  • 92
1

Have a look at the DBUnit library - it's designed to perform the actions you're describing. It can create & tear down database instances and provides you with simple ways to do this.

TrueDub
  • 5,000
  • 1
  • 27
  • 33
-1

Though accepted answer is clever, seems hacky. Have you tried using a normal Constructor?

public class MyJUnitTest {

    public MyJUnitTest() {
       // code for initializeDB
    }

    // Tests

}
Arun Avanathan
  • 982
  • 4
  • 11
  • 26
  • This won't work. JUnit creates a new instance of the testing class for each \@Test. So using the constructor is effectively the same as \@Before, not \@BeforeClass – Azianese Dec 04 '19 at 04:09
-2

Try this solution: https://stackoverflow.com/a/46274919/907576 :

with @BeforeAllMethods/@AfterAllMethods annotations you could execute any method in Test class in an instance context, where all injected values are available.

radistao
  • 14,889
  • 11
  • 66
  • 92
  • 1
    This doesn't work because these annotations don't exist in a spring boot application. The question clearly says Spring boot application! Don't give advice that doesn't work. – Martijn Hiemstra Dec 24 '18 at 09:29
  • In the mentioned solution there are references to the dependencies with the annotations. Because stackoverflow doesn't allow duplicate answers i just mentioned the references to another more descriptive answer. – radistao Dec 24 '18 at 09:53