Search code examples
javaspringspring-mvcjunitjunit4

ClassCastException: org.springframework.beans.factory.support.NullBean cannot be cast to org.springframework.plugin.core.Plugin


I have this test in my app:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = ApplicationTestConfig.class)
@MockBeans({ @MockBean(SwaggerConfig.class)})
public class AuthorisationControllerTest implements WebMvcConfigurer {

    private MockMvc mockMvc;

    @Autowired
    private WebApplicationContext wac;


    @Before
    public void setup() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
    }

    @Test
    public void testAuthorisation() throws Exception {
        this.mockMvc.perform(get("/test")).andDo(print()).andExpect(status().isOk())
                .andExpect(content().string(containsString("Hello, World")));
    }


}

but when I run the test I got this error:

15:04:10.417 [main] ERROR org.springframework.test.context.TestContextManager - Caught exception while allowing TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener@7219ec67] to prepare test instance [eu.europa.ec.oib.kw.guards.controller.AuthorisationControllerTest@6fb219dd]
java.lang.IllegalStateException: Failed to load ApplicationContext
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:132)
    at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:123)
    at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:190)
    at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:132)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:244)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:227)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:246)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
    at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
    at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:365)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:273)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:238)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:159)
    at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:384)
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:345)
    at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:126)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:418)
Caused by: org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.ClassCastException: org.springframework.beans.factory.support.NullBean cannot be cast to org.springframework.plugin.core.Plugin
    at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:185)
    at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:53)
    at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:360)
    at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:158)
    at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:122)
    at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:895)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:554)
    at org.springframework.test.context.web.AbstractGenericWebContextLoader.loadContext(AbstractGenericWebContextLoader.java:129)
    at org.springframework.test.context.web.AbstractGenericWebContextLoader.loadContext(AbstractGenericWebContextLoader.java:61)
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:275)
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:243)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
    ... 28 common frames omitted
Caused by: java.lang.ClassCastException: org.springframework.beans.factory.support.NullBean cannot be cast to org.springframework.plugin.core.Plugin
    at org.springframework.plugin.core.PluginRegistrySupport.initialize(PluginRegistrySupport.java:78)
    at org.springframework.plugin.core.OrderAwarePluginRegistry.initialize(OrderAwarePluginRegistry.java:132)
    at org.springframework.plugin.core.PluginRegistrySupport.getPlugins(PluginRegistrySupport.java:59)
    at org.springframework.plugin.core.SimplePluginRegistry.getPlugins(SimplePluginRegistry.java:68)
    at springfox.documentation.spring.web.plugins.DocumentationPluginsManager.documentationPlugins(DocumentationPluginsManager.java:96)
    at springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper.start(DocumentationPluginsBootstrapper.java:162)
    at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:182)
    ... 40 common frames omitted
15:04:10.436 [main] DEBUG org.springframework.test.context.support.AbstractDirtiesContextTestExecutionListener - After test class: context [DefaultTestContext@769e7ee8 testClass = AuthorisationControllerTest, testInstance = [null], testMethod = [null], testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@5276e6b0 testClass = AuthorisationControllerTest, locations = '{}', classes = '{class com.bonanza.ApplicationTestConfig}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@491666ad, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@51931956, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@82791545, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@240237d2, org.springframework.test.context.web.socket.MockServerContainerContextCustomizer@212bf671], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.test.context.web.WebDelegatingSmartContextLoader', parent = [null]], attributes = map[[empty]]], class annotated with @DirtiesContext [false] with mode [null].
[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 10.803 s <<< FAILURE! - in com.bonanza..controller.AuthorisationControllerTest
[ERROR] testAuthorisation(om.bonanza.controller.AuthorisationControllerTest)  Time elapsed: 0.049 s  <<< ERROR!
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.ClassCastException: org.springframework.beans.factory.support.NullBean cannot be cast to org.springframework.plugin.core.Plugin
Caused by: java.lang.ClassCastException: org.springframework.beans.factory.support.NullBean cannot be cast to org.springframework.plugin.core.Plugin
[INFO] 

Solution

  • Probably your problem could be related with the following line:

    @MockBeans({ @MockBean(SwaggerConfig.class)})
    

    I think Spring is trying to mock your Swagger configuration and, when resolving dependencies, the framework is providing a NullBean reference instead of the required object, an instance of org.springframework.plugin.core.Plugin in this case.

    I assume that you need to disable Swagger support in your tests.

    If that is the case, there is a simpler way to proceed.

    The idea is combine Spring profiles.

    First, define a @Profile annotation in your Swagger class configuration, like:

    @Profile("swagger")
    @Configuration
    @EnableSwagger2
    public class SwaggerConfig {
      //...
    }
    

    This profile should be included in your normal application operation. Please, let me know if you need further information on this.

    Then, in your test, select the profiles you want to enable with the @ActiveProfiles annotation, for instance:

    @RunWith(SpringJUnit4ClassRunner.class)
    @WebAppConfiguration
    @ContextConfiguration(classes = ApplicationTestConfig.class)
    @ActiveProfiles("test")
    public class AuthorisationControllerTest implements WebMvcConfigurer {
    

    You can define, as in the example, a single profile of name test that includes a list of profiles, or directly include the list of profiles applicable, just be sure to not include the one associated with the Swagger configuration, swagger in the example.

    Or, if it does not interfere with other of your configurations, you can achieve a similar result with the following configuration:

    @Profile("!no-swagger")
    @Configuration
    @EnableSwagger2
    public class SwaggerConfig {
      //...
    }
    

    And your test:

    @RunWith(SpringJUnit4ClassRunner.class)
    @WebAppConfiguration
    @ContextConfiguration(classes = ApplicationTestConfig.class)
    @ActiveProfiles("no-swagger")
    public class AuthorisationControllerTest implements WebMvcConfigurer {