JUnit: @Before only for some test methods?
Asked Answered
D

7

86

I have some common set up code that I've factored out to a method marked with @Before. However, it is not necessary for all this code to run for every single test. Is there a way to mark it so the @Before method only runs before certain tests?

Destructive answered 10/10, 2009 at 16:53 Comment(0)
B
61

Just move out the tests that don't need the setup code into a separate test class. If you have some other code common to the tests that would be helpful to keep, move that out into a helper class.

Burbage answered 10/10, 2009 at 16:55 Comment(2)
real helpful @Burbage :( - "do it right in the first place"Denoting
This isn't an answer, to be honest. I'm in a situation where I really shouldn't move the test to another class, but I'd like to avoid executing the @BeforeMethod before one out of several dozen tests.Redneck
C
53

@Nested + @BeforeEach

Totally agree with the point of moving the related code to an inner class. So here what I have done.

  1. Create an inner class inside your test class
  2. Annotate the inner class with @Nested
  3. Move all the test methods you want to use in the inner class
  4. Write the init code inside the inner class and annotate it with @BeforeEach

Here is the code:

class Testing {

    @Test
    public void testextmethod1() {
    
      System.out.println("test ext method 1");
    
    }
    
    @Nested
    class TestNest{
    
       @BeforeEach
       public void init() {
          System.out.println("Init");
       }
    
       @Test
       public void testmethod1() {
          System.out.println("This is method 1");
       }
    
       @Test
       public void testmethod2() {
          System.out.println("This is method 2");
       }
    
       @Test
       public void testmethod3() {
          System.out.println("This is method 3");
       }
        
     }

     @Test
     public void testextmethod2() {
    
         System.out.println("test ext method 2");
    
     }

}

Here is the output

test ext method 1
test ext method 2
Init
This is method 1
Init
This is method 2
Init
This is method 3

Note: I am not sure if this is supported in Junit4. I am doing this in JUnit5

Clearway answered 29/10, 2019 at 10:10 Comment(4)
Did u mean @BeforeEach instead of @ForEach ?Peterec
Thanks, @DevanshSharma for pointing it out. Corrected the typo.Clearway
I think there is still one @ForEach left in the answer, that could be improved. Thanks for the answer.Fixity
@misteeque corrected the typo. ThanksClearway
L
9

It is possible to achieve also via Assume from JUnit. And then you can check the method name for which you want to process @Before.

public class MyTest {
     @Rule
     public TestName testName = new TestName();

     @Before
     public void setUp() {
       assumeTrue(testName.getMethodName().equals("myMethodName"));
       // setup follows
     }
}

Check the topic for more insights about @Rule.

Leach answered 10/3, 2015 at 21:3 Comment(3)
Don't use assume, it stops the whole test from running, not just the @Before method. if(!testName.getMethodName().equals("myMethodName")) {return;} (excuse the spacing) would work better.Archaeo
I frankly find the "if-test-name-equals" idea pointless, as you might as well just call the before and after function directly in the tests that need them, and eliminate the Before and After annotations.Rogue
@Rogue "... as you might as well just call the before and after function directly in the tests that need them..." - No, you can't! Sometimes, special annotations prevent from doing so. For example, @ Transactional annotation, which covers a @ Test method with a transaction implicitly. And, if you need to test concurrent behavior, you have to open another transaction somewhere outside the @ Test method!Koval
G
3

Now that it's 2023, I'd recommend sticking with JUnit 5.x

I'd also say that this is probably a micro-optimization. I would not go to the effort until I measured my test time and saw that running the code when it wasn't necessary added a significant amount of time.

Genital answered 10/10, 2009 at 17:36 Comment(2)
could you provide some more clarification?Manor
Could you please provide an example?Redneck
H
1

Not sure about @Before, but I recently came up with a strategy for @After block to run selectively. The implementation was straight forward. I have some flags set to default values as part of the test class. They are reset to default values in @Before class. In the class I need to do things specific to a flag, I set those flags & in @After I check for flag values to do the respective jobs.

Hostetler answered 3/7, 2017 at 10:56 Comment(1)
can you give an example ?Tripp
A
0

JUnit 4.12 provide Enclosed Runner like

@RunWith(Enclosed.class) 
public class GlobalTest{

    @RunWith(MockitoJUnitRunner.class)
    public class InnerTest{
    
    }

}
Aetolia answered 7/8, 2020 at 0:17 Comment(0)
B
0

Alternative to @Nested on JUnit4 :

@RunWith(Suite.class)
@SuiteClasses({Testing.TestWithoutBefore.class, Testing .TestWithBefore.class})
public class Testing {

    static class TestWithoutBefore{
       @Test
       public void testmethod1() {
          System.out.println("This is method 1");
       }
    
       @Test
       public void testmethod2() {
          System.out.println("This is method 2");
       }
    
       @Test
       public void testmethod3() {
          System.out.println("This is method 3");
       }
     }
    
    static class TestWithBefore{
       @Before
       public void init() {
          System.out.println("Init");
       }
    
       @Test
       public void testmethod1() {
          System.out.println("This is method 1");
       }
    
       @Test
       public void testmethod2() {
          System.out.println("This is method 2");
       }
    
       @Test
       public void testmethod3() {
          System.out.println("This is method 3");
       }
     }
}
Bargello answered 28/6 at 14:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.