88

Are there any best practices to get Junit execute a function once in a test file , and it should also not be static.

like @BeforeClass on non static function?

Here is an ugly solution :

@Before void init(){
    if (init.get() == false){
        init.set(true);
        // do once block
    }
}

well this is something i dont want to do , and i am looking for an integrated junit solution.

Roman
  • 7,933
  • 17
  • 56
  • 72
  • Well , i have a quite a big hierarchy of test files , and base test files , i need the possibility to override this action in the child test classes. – Roman May 13 '10 at 09:39
  • 1
    i had the same problem in which only the first of many parametrized tests should perform a login. – dokaspar Oct 05 '12 at 14:27
  • 5
    Note that the "ugly" solution, the one that works with plain JUnit, don't take tearing tests down into account. – eskatos Oct 30 '13 at 12:11

8 Answers8

44

A simple if statement seems to work pretty well too:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:test-context.xml"})
public class myTest {

    public static boolean dbInit = false;

    @Autowired
    DbUtils dbUtils;

    @Before
    public void setUp(){

        if(!dbInit){

            dbUtils.dropTables();
            dbUtils.createTables();
            dbInit = true;

        }
    }

 ...
Upgradingdave
  • 12,916
  • 10
  • 62
  • 72
  • 1
    Nice and simple! But can't see a way of simply adapting this to make a non-static `@AfterClass` equivalent that tears down after all the tests have run? – Steve Chambers Jun 27 '15 at 07:16
  • 2
    See [here](http://stackoverflow.com/questions/12087959/junit-run-set-up-method-once/31117171#31117171) for an update to this method that should work for test classes that use inheritance. – Steve Chambers Jun 30 '15 at 09:59
37

To use an empty constructor is the easiest solution. You can still override the constructor in the extended class.

But it's not optimal with all the inheritance. That's why JUnit 4 uses annotations instead.

Another option is to create a helper method in a factory/util class and let that method do the work.

If you're using Spring, you should consider using the @TestExecutionListeners annotation. Something like this test:

@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({CustomTestExecutionListener.class, 
     DependencyInjectionTestExecutionListener.class})
@ContextConfiguration("test-config.xml")
public class DemoTest {

Spring's AbstractTestExecutionListener contains for example this empty method that you can override:

public void beforeTestClass(TestContext testContext) throws Exception {
    /* no-op */
}

NOTE: DO NOT overlook/miss DependencyInjectionTestExecutionListener while adding custom TestExecutionListeners. If you do, all the autowires will be null.

Anand Rockzz
  • 6,072
  • 5
  • 64
  • 71
Espen
  • 10,545
  • 5
  • 33
  • 39
23

If you don't want to set up static initializers for one time initialization and are not particular about using JUnit, take a look at TestNG. TestNG supports non-static, one-time initialization with a variety of configuration options, all using annotations.

In TestNG, this would be equivalent to:

@org.testng.annotations.BeforeClass
public void setUpOnce() {
   // One time initialization.
}

For teardown,

@org.testng.annotations.AfterClass
public void tearDownOnce() {
   // One time tear down.
}

For the TestNG equivalent of JUnit 4's @Before and @After, you can use @BeforeMethod and @AfterMethod respectively.

cdeszaq
  • 30,869
  • 25
  • 117
  • 173
Kartik
  • 2,541
  • 2
  • 37
  • 59
8

Easily use @BeforeAllMethods/@AfterAllMethods annotations to run a method inside the instance context (non-static), where all injected values will be available.

There is a special testing library for this:

https://mvnrepository.com/artifact/org.bitbucket.radistao.test/before-after-spring-test-runner/0.1.0

https://bitbucket.org/radistao/before-after-spring-test-runner/

The only limitation: works only for Spring testing.

(I'm the developer of this testing library)

radistao
  • 14,889
  • 11
  • 66
  • 92
0

UPDATE: Please see the comment by Cherry for why the suggestion below is flawed. (Am keeping the answer on here rather than deleting as the comment may provide useful information to others as to why this doesn't work.)


Another option worth considering if using dependency injection (e.g. Spring) is @PostConstruct. This will guarantee dependency injection is complete, which wouldn't be the case in a constructor:

@PostConstruct
public void init() {
    // One-time initialization...
}

Steve Chambers
  • 37,270
  • 24
  • 156
  • 208
  • 8
    Very **bad** solution in case of Junit tests. Junit creates test class instance everytime when it runs a test method. So if there 6 test methods in class, a class constructor, `@Before` and `@After` methods will be called 6 times! So in this context `@PostConstruct` behaves like `@Before` annotation. You can simply test it: just put 2 test methods in test class, add `@PostConstruct public void init() {System.out.println("started");}` and see in logs how many time it is printed. – Cherry Oct 01 '14 at 06:02
  • For info I just came across the [JUnit documentation](http://junit.sourceforge.net/javadoc/org/junit/Test.html) that confirms what's described in the comment above about JUnit creating an instance for each `@Test` run: *"To run the method, JUnit first constructs a fresh instance of the class then invokes the annotated method."* – Steve Chambers Sep 14 '17 at 15:01
0

The article discuss 2 very nice solutions for this problem:

  1. "clean" junit with custom Runner (using interface but you could extend it with a custom annotation e.g. @BeforeInstance)
  2. Spring execution listeners as mentioned by Espen before.
kedzi
  • 89
  • 1
  • 5
0

I've never tried but maybe you can create a no-argument constructor and call you function from there?

Roman
  • 64,384
  • 92
  • 238
  • 332
  • This would work , the problem is that I need the possibility to override this action in the classes that extend this base test class – Roman May 13 '10 at 09:38
  • @Roman: oh, now I see. Add this to your post, this comment makes things much clearer. – Roman May 13 '10 at 09:57
  • Constructor will be called as many times the test cases are there. For each test method, new Test class object will be created. So, using constructor is not a solution here – manikanta Sep 27 '11 at 18:46
  • Also this wont work with dependency injection that relies on the object already constructed. – Mike Miller Mar 22 '12 at 18:33
-5

Just use @BeforeClass:

@BeforeClass
public static void init() {
}

It doesn't make sense for init to be non-static because each test is run in a separate instance. The instance that init is run on would not match the instance of any test.

The only reason that you might want it to be non-static is to override it in subclasses, but you can do this with static methods too. Just use the same name, and only the subclass init method will be called.

fgb
  • 18,439
  • 2
  • 38
  • 52
  • 4
    This whole question is about the possibility to do it in a non-static way, which is needed if you need some instance-variables on the class. – Simon Forsberg Feb 02 '17 at 09:11
  • @SimonForsberg Yes, and I'm saying the question is an XY problem. The op said the problem was overriding the behavior in child classes. If the example needed instance variables, then I might suggest something else. – fgb Feb 02 '17 at 13:48
  • See this comment: http://stackoverflow.com/questions/2825615/junit-before-class-non-static/27730780?noredirect=1#comment2866266_2825615 – Simon Forsberg Feb 02 '17 at 16:45
  • @SimonForsberg That's the comment I was talking about. What about it? – fgb Feb 02 '17 at 17:14