ClassCastException:GenericApplicationContext cannot be cast to org.springframework.web.context.WebApplicationContext - spring

It is a spring boot project and it uses XML for creation of bean. Now I am writing test case and while doing the same I am facing the class cast Exception while a creating a particular bean
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest()
#TestPropertySource("classpath:application.properties")
#WebAppConfiguration
#ContextConfiguration(loader=AnnotationConfigContextLoader.class)
public class ApplicationTests {
private MockMvc mockMvc;
#Autowired
private WebApplicationContext wac;
#Before
public void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
<bean id="springUtility"
class="com.endeca.infront.web.spring.SpringUtility" scope="singleton" />````
Above is the bean
Error : Caused by: java.lang.ClassCastException: org.springframework.context.support.GenericApplicationContext cannot be cast to org.springframework.web.context.WebApplicationContext

You can directly inject MockMvc and omit some of your configuration because it's the default.
So your test class will look like this:
#SpringBootTest
#RunWith(SpringRunner.class)
public class ApplicationTests {
#Autowired
private MockMvc mockMvc;
// Add your tests
}
If you need to load configuration #ImportResource is the prefered way. Simply put it on the #SpringBootApplication or a #Configuration class.
#ImportResource({"classpath*:applicationContext.xml"})

Related

How to #Autowired a test controller invoked by WebTestClient in #WebFluxTest?

I have a Controller just for tests with dummy apis
#RestController
public class TestController {
#Autowired
private org.springframework.cloud.sleuth.Tracer tracer;
#GetMapping("/trace")
public Mono<String> traceTest() {
...
}
}
Here's my test
#WebFluxTest(controllers = TestController.class)
public MyTest {
#Autowired
private WebTestClient webClient;
#Test
public void testTrace() {
webClient.get().uri("/trace")...
}
}
When I try to run this, my Tracer is not Autowired.
Of course, if I change my test to a #SpringBootTest, it all works
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public MyTest {
...
}
But I'd like to avoid autowiring my entire spring application. How can I get TestController to be auto-configured?
The #WebFluxTest annotation populates a Spring TestContext with only a subset of the relevant beans:
#WebFluxTest auto-configures the Spring WebFlux infrastructure and
limits scanned beans to #Controller, #ControllerAdvice,
#JsonComponent, Converter, GenericConverter, WebFilter, and
WebFluxConfigurer. Regular #Component and #ConfigurationProperties
beans are not scanned when the #WebFluxTest annotation is used.
#EnableConfigurationProperties can be used to include
#ConfigurationProperties beans. from Spring Boot Documentation
Your Tracer won't be part of this TestContext out-of-the-box.
For your #WebFluxTest you can provide a mocked version of this bean with #MockBean:
#WebFluxTest(controllers = TestController.class)
public MyTest {
#Autowired
private WebTestClient webClient;
#MockBean
private Tracer tracer;
#Test
public void testTrace() {
webClient.get().uri("/trace")...
}
}
... and if you want to test the full integration I would rather use #SpringBootTest.

Mock any Spring Bean in Test Class

I have Test class which I am using to test some mongo queries.
My applicationContext-mongoclient.xml contents mongodb connection string.
I have my dao class which is annotated as #component and this mongoDatadase is autowired to dao
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:applicationContext-mongoclient.xml" })
public class ApplicationContextInitTest {
#Autowired
MongoDatabase mongoDatabase;
MyDao myDao;
#Before
public void setMyDao(){
estimateServicesLookup = Mockito.mock(EstimateServicesLookup.class);
ReflectionTestUtils.setField(estimateServicesLookup,"mongoDatabase",mongoDatabase);
//#Test code here which is taking results from myDao and asserting.
}
}
Above code is not working and looks like I am not getting mongoDatabase in my dao.
Can anyone suggest how we can do it?

Custom filter not injected in Spring integration test

I have an integration test that is designed to start my Spring Boot app:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = AppConfigCorrelationIdTestIt.class)
#WebIntegrationTest("server.port:0")
public class CorrelationIdTestIT {
Where the configuration class is:
#EnableConfigurationProperties
#ComponentScan
#EnableAutoConfiguration
#Configuration
public class AppConfigCorrelationIdTestIt {
In the app I have a defined custom servlet filter:
public class CorrelationHeaderFilter implements Filter {
But when testing my app I'm finding that the customer filter isn't instantiated and injected in to the filter chain. The only way round this I've found is to manually create it as a bean in AppConfigCorrelationIdTestIt, and then it works perfectly.
#Bean
public CorrelationHeaderFilter correlationHeaderFilter() {
return new CorrelationHeaderFilter();
}
Any ideas why the filter isn't picked up by Spring Boot when the application starts?
Thanks
Usually, in test classes possible to use DefaultMockMvcBuilder.addFilter(Filter filter, String... urlPatterns) when configured MockMvc. For example:
#WebAppConfiguration
#ContextConfiguration
public class AuthenticationTest {
private static final String TOKEN_HEADER = "X-Firebase-Auth";
final String url = "http://localhost:8080/authentication";
final Logger logger = LoggerFactory.getLogger(AuthenticationTest.class);
#Autowired
private WebApplicationContext webApplicationContext;
#Autowired
public Filter springSecurityFilterChain;
private MockMvc mockMvc;
#Before
public void setUp(){
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.addFilter(springSecurityFilterChain).build();
}
...
}
I based on this answer

#SpringApplicationConfiguration without #IntegrationTest

right now, I start my Spring Boot Integration tests with
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = {Application.class})
#WebAppConfiguration
#org.springframework.boot.test.IntegrationTest
#ActiveProfiles("it")
public class AbstractIntegrationTest {
protected MockMvc mockMvc;
#Inject
private EmbeddedWebApplicationContext webApplicationContext;
#Inject
private RequestHeaderAuthenticationFilter requestHeaderAuthenticationFilter;
#Before
public void mockMvcSetUp() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.addFilter(requestHeaderAuthenticationFilter)
.build();
}
}
However, this always starts a fully leaded servlet container that listens on a port because my Application.class is annotated with #EnableAutoConfiguration.
Since I use MockMvc instead of RestTemplates (I like the fluent interface of MockMvc way more than RestTemplates), I figure it should be possible to not start a fully loaded container.
Could anyone please educate me if this is possible and if so, how?
Thanks,
Robin

Spring HATEOAS Resource assembler is not instantiated in unit test

I am trying to write a unit test for a REST controller which generates HATEOAS links via Resource assembler class. Everything is OK in production, but with the unit test Resource assembler class is not being injected into the controller.
my resource assembler class is:
#Component
public class ModelResourceAssembler extends ResourceAssemblerSupport<Model, ModelResource> {
public ModelResourceAssembler() {
super(ModelRestController.class, ModelResource.class);
}
#Bean
public ModelResourceAssembler modelResourceAssembler(){
return new ModelResourceAssembler();
}
#Override
public ModelResource toResource(Model model) {
...
}
}
The controller is:
#Controller
#RequestMapping("/demo")
#ComponentScan(basePackages = {"com.foo.demo"} )
public class ModelRestController {
#Autowired
private ModelPersistenceHandler modelPersistenceHandler;
#Autowired
private ModelResourceAssembler modelResourceAssembler;
...
}
And the unit test:
#RunWith(MockitoJUnitRunner.class)
#ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes= {ModelResourceAssembler.class, ModelRestController.class})
public class ModelRestControllerTest {
private MockMvc mockMvc;
#InjectMocks
private ModelRestController modelRestController;
#Mock
private ModelPersistenceHandler modelPersistenceHandler;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(modelRestController).build();
}
...
}
No matter what I do the ModelResourceAssembler instance is always null. Since the application is Spring Boot it does not have the WebCoonfig classes and autowired WebApplicationContext is always null, so I cannot (and really don't want to since I am running a unit test) instantiate MockMvc via webAppContextSetup
The solution ended up being quite simple: I needed to add one line to my test:
#Spy
private ModelResourceAssembler modelResourceAssembler;
And the bean was instantiated and properly wired
In your example you use #InjectMocks but don't declare a mock for ModelResourceAssembler. You don't get an instance out of nowhere.
You use the MockitoJUnitRunner.class. It has no idea of Spring beans. For testing Spring applications you rather want to use SpringJUnit4ClassRunner.class.
If i may suggest, if you use constructor injection for your controller then you can just mock the dependency and not need spring junit test runner stuff.

Resources