44

I have started testing and now i want to use @After, @Before and @Test but my application only runs the @Before method and gives output on console

before

However, if I remove @After and @Before it runs the @Test. My code is here:

public class TestPractise extends AbstractTransactionalDataSourceSpringContextTests{

    @Before
    public void runBare(){
        System.out.println("before");
    }

    @Test
    public void testingMethod(){
        System.out.println("testing");
    }

    @After
    public void setDirty(){
        System.out.println("after");
    }
}

Why aren't @After, @Test and @before working simultaneously?

assylias
  • 321,522
  • 82
  • 660
  • 783
abhishek ameta
  • 2,326
  • 7
  • 28
  • 35

8 Answers8

69

Use @BeforeEach instead of @Before and @AfterEach instead of @After.

anothernode
  • 5,100
  • 13
  • 43
  • 62
vikram k
  • 807
  • 1
  • 6
  • 2
  • 8
    Could you add a little bit of an explanation about why and how this solves the problem? – anothernode Jul 25 '18 at 09:48
  • 3
    In my case my "@Before" and "@After" code was not running, but it worked when i replaced "@Before" with "@BeforeEach" and "@After" and "@AfterEach". – vikram k Jul 26 '18 at 07:13
  • It's just more specific names working is same. But support (Execution) is depends on Junit version. – vikram k Jul 26 '18 at 07:19
  • 2
    dude! I spent hours figuring this out! – sschrass May 06 '19 at 13:16
  • 1
    Just keep in mind this creates alot of wasted execution. BeforeEach resets everything *before* every test is run. This could be desirable but unnecessary for example, when loading a file for test parameters or one-time file reads for the class. – avgvstvs Mar 03 '20 at 14:29
21

The AbstractTransactionalDataSourceSpringContextTests class forces the use of the old JUnit 3.x syntax, which means that any of the JUnit 4 annotation will not work.

Your method runBare() is executed not because of the @Before annotation, but because it is named runBare(), which is a method provided by ConditionalTestCase and JUnit TestCase class.

So you have 2 solutions:

  • Use the AlexR answer to use JUnit 4 tests and Spring;
  • Keep your inheritance of AbstractTransactionalDataSourceSpringContextTests, but use the onSetUp and onTearDown methods instead of the @Before and @After methods.
Romain Linsolas
  • 79,475
  • 49
  • 202
  • 273
  • 1
    Got this same problem mixing up JUnit 4 and 5. Check your imports for the annotations and make sure they match. – Muhd Jun 20 '17 at 06:08
18

Check that you are using Junit4 because from Junit5 onwards @Before/@After is now @BeforeEach/@AfterEach and similalry @BeforeClass/@AfterClass is @AfterAll/@BeforeAll.

Anurag Bharti
  • 181
  • 1
  • 3
7

It should work... But since you are working with spring framework and JUnit 4 was introduced years ago I's suggest you to use annotations instead of inheritance.

So, annotate you class with @RunWith(SpringJUnit4ClassRunner.class). Remove extends AbstractTransactionalDataSourceSpringContextTests.

Don't forget to make the @Before and @After methods static

Now it should work.

Even if you want to extend Spring abstract test classes at least pay attention that some of them are deprecated. For example class AbstractTransactionalDataSourceSpringContextTests is deprecated.

Franz Ebner
  • 4,951
  • 3
  • 39
  • 57
AlexR
  • 114,158
  • 16
  • 130
  • 208
6

JUnit Jupiter, aka "JUnit 5": use @BeforeAll

If you use the newer JUnit Jupiter (Java 8 onward), you'll want to replace @Before with @BeforeAll.

Furthermore, you'll need to either annotate your test class with @TestInstance(Lifecycle.PER_CLASS) or make the @BeforeAll method static. Here's an example:

@TestInstance(Lifecycle.PER_CLASS)
class MyTestClass {

    MyHeavyResource sharedResource;

    @BeforeAll
    void init() {
        System.out.println("init");
        sharedResource = new MyHeavyResource(1234);
    }

    @Test
    void myTest() {
        System.out.println("myTest");
        sharedResource.methodUnderTest();
    }
}

Understanding Lifecycle.PER_CLASS

The likely reason JUnit 5 is more stringent with this -- demanding either static or Lifecycle.PER_CLASS -- is that it wants the test author to acknowledge that any resource instance initialized in a @BeforeAll method will genuinely be shared across each individual unit test method within the class. This could compromise their isolation, for example if the sharedResource in the above example isn't stateless/idempotent.

If sharedResource cannot be safely shared (or if it's reasonably leightweight), the init method should be annotated with @BeforeEach instead, which would create a new instance before executing each individual test within the class.

The Javadoc for TestInstance explain how using Lifecycle.PER_CLASS actually enforces a single instance of the test class; whereas the behaviour of JUnit 4 and earlier was equivalent to Lifecycle.PER_METHOD, which created a new instance of the test class for each @Test method contained therein. This would somewhat mislead the author to suppose that @Before was only executed once for each of those tests.

sxc731
  • 2,418
  • 2
  • 28
  • 30
3

If you use auto import in an IDE, make sure the @Test and @Before are imported from the org.junit package.

user514949
  • 79
  • 2
  • 6
0

in my case, I had that problem the solution was to change the java access modifier, It was way private.

before (not working) @Test void validate() throws Exception {}

after (working) @Test public void validate() throws Exception {}

0
  • In my case I just moved stuff from @Before / @BeforeEach annotated setUp() method to the constructor of my unit-test class.
  • As per this thread using constructor is 'equivalent' to @Before method

I can't explain why it fixed the problem but I was facing this in one particular class and it did indeed do the trick.

y2k-shubham
  • 10,183
  • 11
  • 55
  • 131