64

Spring support JUnit quite well on that: With the RunWith and ContextConfiguration annotation, things look very intuitive

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:dao-context.xml")

This test will be able to run both in Eclipse & Maven in correctly. I wonder if there is similar stuff for TestNG. I'm considering moving to this "Next Generation" Framework but I didn't find a match for testing with Spring.

Phương Nguyễn
  • 8,747
  • 15
  • 62
  • 96

3 Answers3

64

It works with TestNG as well. Your test class needs to extend one of the following classes:

informatik01
  • 16,038
  • 10
  • 74
  • 104
lexicore
  • 42,748
  • 17
  • 132
  • 221
  • 7
    What a mess. Firstly enforces specific class hierarchy. Secondly is quite confusing as test case that uses `@Transactional` can extends non-transactional version by mistake. But unfortunately there is no other way to use a Spring with TestNG. – G. Demecki Oct 22 '14 at 09:53
  • 1
    @GrzesiekD. My hope is that something may have changed in 4.5 years. :) So please recheck the status quo. – lexicore Oct 22 '14 at 09:55
  • first don't work for me, but second is ok. so what's the difference with and without transactional ? – mik3fly-4steri5k May 27 '18 at 18:22
32

Here is an example that worked for me:

import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.annotations.Test;

@Test
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class TestValidation extends AbstractTestNGSpringContextTests {

    public void testNullParamValidation() {
        // Testing code goes here!
    }
}
Arup Malakar
  • 543
  • 6
  • 9
24

Spring and TestNG work well together, but there are some things to be aware of. Aside from subclassing AbstractTestNGSpringContextTests, you need to be aware of how it interacts with standard TestNG setup/teardown annotations.

TestNG has four levels of setup

  • BeforeSuite
  • BeforeTest
  • BeforeClass
  • BeforeMethod

which occur exactly as you would expect (great example of self-documenting APIs). These all have an optional value called dependsOnMethods which can take a String or String[], which is the name or name(s) of the methods at the same level.

The AbstractTestNGSpringContextTests class has a BeforeClass annotated method called springTestContextPrepareTestInstance, which you must set your setup method to depend on if you are using an autowired class in it. For methods, you don't have to worry about the autowiring, since it occurs when the test class is setup in that before class method.

This just leaves the question of how you might use an autowired class in a method annotated with BeforeSuite. You can do this by manually calling springTestContextPrepareTestInstance - while its not setup by default to do this, I've done it several times successfully.

So, to illustrate, a modified version of Arup's example:

import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.annotations.Test;

@Test
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class TestValidation extends AbstractTestNGSpringContextTests {

    @Autowired
    private IAutowiredService autowiredService;

    @BeforeClass(dependsOnMethods={"springTestContextPrepareTestInstance"})
    public void setupParamValidation(){
        // Test class setup code with autowired classes goes here
    }

    @Test
    public void testNullParamValidation() {
        // Testing code goes here!
    }
}
Saikat
  • 14,222
  • 20
  • 104
  • 125
romeara
  • 1,426
  • 1
  • 17
  • 26
  • The method org.springframework.test.context.testng.AbstractTestNGSpringContextTests#springTestContextPrepareTestInstance already has the annotation @BeforeClass so this solution appear to me as redundant. – Christian Nilsson Jul 08 '14 at 09:37
  • 1
    This solution allows you to add autowire-field dependent code to your test. "springTestContextPrepareTestInstance" being a "before class" method doesn't guarantee that it will run before the "before class" of a sub-class - you need to explicitly set the dependsOnMethods field – romeara Aug 26 '14 at 20:39
  • 2
    Unfortunately this doesn't work for me. By default, the `@Autowire` seems to take place VERY late, after @BeforeTest (but before @Test). I tried adding the dependsOnMethods, but then I get: MyClass is depending on method protected void org.springframework.test.context.testng.AbstractTestNGSpringContextTests.springTestContextPrepareTestInstance() throws java.lang.Exception, which is not annotated with @Test... – dmansfield May 01 '15 at 20:17
  • Edit: just found a solution (problem was BeforeSuite doesn't work with this). Check: http://stackoverflow.com/questions/5192562/spring-autowiring-happens-after-beforeclass-when-running-test-with-maven-surefi – dmansfield May 01 '15 at 20:42
  • What if i want to access beans in Listener? It seems if you add @Listener, it gets initialized before the AbstractTestNGSpringContextTests methods are called – Johnyb Feb 23 '23 at 14:18