Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 822
Gowri Shankar Avatar asked Aug 27 '14 21:08

Gowri Shankar


2 Answers

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 {

}
like image 161
Andy Wilkinson Avatar answered Nov 20 '22 18:11

Andy Wilkinson


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

like image 1
Łukasz Chorąży Avatar answered Nov 20 '22 19:11

Łukasz Chorąży