Gowri Shankar
Gowri Shankar

Reputation: 161

Integration testing a Spring Boot web app with TestNG

We recently integrated our application with spring boot. Our test cases are based on testng framework. Our base test class looks like the following

      @SpringApplicationConfiguration(classes = Application.class)
      @ActiveProfiles(profiles = "test")
      @WebAppConfiguration
      @IntegrationTest
      public class BaseTestCase extends AbstractTestNGSpringContextTests {
      }

We defined the above class to set up the active profile and load the application context. All the integration test classes extends BaseTestCase

One of our basic test case looks like below

       @Test
       public void testPing() throws Exception{
          RestTemplate restTemplate = new RestTemplate();
          String response = restTemplate.getForObject(
                    <some url>,
                    String.class);
          Assert.assertNotNull(response);
        }

When we run the above test case, we get the following exception

FAILED CONFIGURATION: @BeforeClass springTestContextPrepareTestInstance
java.lang.IllegalStateException: The WebApplicationContext for test context [DefaultTestContext@11b72c96 testClass = DataResourceTest, testInstance = com.xactly.insights.resource.imp.DataResourceTest@5b630a31, testMethod = [null], testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@10d034f0 testClass = DataResourceTest, locations = '{}', classes = '{class com.xactly.insights.app.Application}', contextInitializerClasses = '[]', activeProfiles = '{test}', resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.SpringApplicationContextLoader', parent = [null]]] must be configured with a MockServletContext.
    at org.springframework.util.Assert.state(Assert.java:385)
    at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:166)
    at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:101)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:331)
    at org.springframework.test.context.testng.AbstractTestNGSpringContextTests.springTestContextPrepareTestInstance(AbstractTestNGSpringContextTests.java:146)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84)
    at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:564)
    at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:213)
    at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:138)
    at org.testng.internal.TestMethodWorker.invokeBeforeClassMethods(TestMethodWorker.java:175)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:107)
    at org.testng.TestRunner.privateRun(TestRunner.java:767)
    at org.testng.TestRunner.run(TestRunner.java:617)
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
    at org.testng.SuiteRunner.run(SuiteRunner.java:240)
    at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
    at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
    at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224)
    at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
    at org.testng.TestNG.run(TestNG.java:1057)
    at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:111)
    at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:204)
    at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:175)

We use spring boot version 1.1.5.RELEASE and testng version 6.1.1. Can someone throw light on how to solve the above issue?

Upvotes: 8

Views: 11870

Answers (2)

Łukasz Chorąży
Łukasz Chorąży

Reputation: 644

I had the same problem. Suprisingly what worked for me was creating SpringContextLoadingTest class, placing all the annotations there, and extending this class instead of AbstractTestNGSpringContextTests

Upvotes: 1

Andy Wilkinson
Andy Wilkinson

Reputation: 116211

The problem is that, by default, AbstractTestNGSpringContextTests enables ServletTestExecutionListener. This listener provides mock Servlet API support to your tests. That's not appropriate in this case as you're running a Spring Boot integration test where the embedded Tomcat server is started for you, providing you with a genuine ServletContext. This leads to the failure that you're seeing as ServletTestExecutionListener asserts that the ServletContext is a MockServletContext instance.

You can fix the problem by disabling inheritance of AbstractTestNGSpringContextTests's test execution listeners and explicitly configuring them using @TestExecutionListeners instead:

@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@IntegrationTest
@TestExecutionListeners(inheritListeners = false, listeners = {
       DependencyInjectionTestExecutionListener.class,
       DirtiesContextTestExecutionListener.class })
public class BaseTestCase extends AbstractTestNGSpringContextTests {

}

Upvotes: 19

Related Questions