spring test fails on mockServletContext unsupportedOperation - spring

I have a set of Integration Tests running for my Spring-Boot 1.3 app. But I had to add the following to get my maximum sessions working:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter implements ServletContextAware {
...
#Override
public void setServletContext(ServletContext servletContext) {
servletContext.getSessionCookieConfig().setHttpOnly(true);
// causes an ApplicationEvent to be published to the Spring ApplicationContext every time a HttpSession commences or terminates
servletContext.addListener(new HttpSessionEventPublisher());
}
...
}
Now when I run my tests, I get the following:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'webSecurityConfig' defined in file [/Users/davidclark/projects/edmtotal/build/classes/main/com/edelweissco/dental/configuration/WebSecurityConfig.class]: Initialization of bean failed; nested exception is java.lang.UnsupportedOperationException
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
...
Caused by: java.lang.UnsupportedOperationException
at org.springframework.mock.web.MockServletContext.addListener(MockServletContext.java:675)
at com.edelweissco.dental.configuration.WebSecurityConfig.setServletContext(WebSecurityConfig.java:123)
...
Here is an example test class (but they all fall with the same exception):
#Transactional
public class ConfigurationSettingsTest extends BaseSpecification {
#Autowired
private ConfigurationSettings configurationSettings;
#Autowired
ConfigurableApplicationContext context
...
}
where BaseSpecification is:
#ContextConfiguration(classes = MyApp, loader = SpringApplicationContextLoader)
#WebAppConfiguration
public class BaseSpecification extends Specification {
#Value('${local.server.port}')
private int serverPort;
def setup() {
RestAssured.port = serverPort;
}
}
It would seem that now when I run my integration tests, a MockServlet is being applied here, and it doesn't support. this feature. When debugging, I see that a SpringBootMockServletContext is trying to be set in setServletContext, and that is where the exception is.

I will post my answer in case anyone else runs into this. The problem was in my BaseSpecification. I added the #WebAppConfiguration and #IntegrationTest to it, and removed #IntegrationTest off the individual integration tests. Apparently this will actually create the ServletContext the way it should be.
#ContextConfiguration(classes = MyApp, loader = SpringApplicationContextLoader)
#WebAppConfiguration
#IntegrationTest
public class BaseSpecification extends Specification {

Related

How to avoid a second Instantiation of a spring bean in child test context

I created an Embedded Sftp server bean for my integration tests, i hooked the startup and the shutdown of the server respectively with the afterPropertiesSet and destroy life cycles
public class EmbeddedSftpServer implements InitializingBean, DisposableBean {
//other class content
#Override
public void afterPropertiesSet() throws Exception {
//Code for starting server here
}
#Override
public void destroy() throws Exception {
//Code for stopping server here
}
}
here my config class
#TestConfiguration
public class SftpTestConfig {
#Bean
public EmbeddedSftpServer embeddedSftpServer() {
return new EmbeddedSftpServer();
}
//Other bean definitions
}
Now when i inject the bean in my test classes like the following :
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = SftpTestConfig .class)
class ExampleOneIT {
#Autowired
private EmbeddedSftpServer embeddedSftpServer;
}
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = SftpTestConfig .class)
class ExampleTwoIT {
#Autowired
private EmbeddedSftpServer embeddedSftpServer;
}
#SpringBatchTest
#ContextConfiguration(classes = SftpTestConfig .class)
class ExampleThreeIT {
#Autowired
private EmbeddedSftpServer embeddedSftpServer;
}
And i run all the test classes simultaneously, i found out that for the test classes annotated with #ExtendWith(SpringExtension.class), it's the same context that is used (which is understandable since i guess spring cache it) and therefore the bean lifecycle methods are not executed again, but to my surprise, for the class annotated with #SpringBatchTest i noticed that the life cycle hooks of the bean are executed again! Which is a behavior that is not convenient since i want the application context to start the server one time for all tests and close it at the end of those tests (which is the case if i use only #ExtendWith(SpringExtension.class) for all my test classes).
N.B. : I need to use #SpringBachTest for my ExampleThreeIT test class.
I think you are hitting this issue: https://github.com/spring-projects/spring-batch/issues/3940 which has been fixed in v4.3.4/4.2.8. Upgrading to one of these versions should fix your issue.

How do I resolve this bean defninition override?

I've upgraded from Spring Boot 1.5 to Spring Boot 2.1.8. I had some tests that were working but are now failing.
I also was using maven-surefire plugin at version 2.9 and it worked, but I upgraded that to 2.22.0 as well, if that matters.
#ExtendWith(SpringExtension.class)
#WebMvcTest(value = ElementController.class, secure = false)
#ContextConfiguration(classes = TestSite1Config.class)
public class ElementControllerSite1IT {
#Autowired
protected MockMvc mvc;
#MockBean
ElementService elementService;
#BeforeEach
public void setup() {
when(elementService.getElementTable( ... )) //skipping args for brevity
.thenReturn(new ElementTable());
}
#Configuration
public static class TestSite1Config {
#Bean
#Autowired
public ElementController elementController(final ElementService elementService) {
return new ElementController(elementService, new ElementControllerProperties(DeploymentLocation.SITE1));
}
#Test
public void failSite1ValidationWithoutId() throws Exception {
ElementParameters params = getParams(false);
mvc.perform(post("/element")
.contentType(JSON)
.andExpect(status().isBadRequest());
}
//more tests, but doesn't matter.
}
There's another class like above, but replace Site1 with Site2.
There is an ElementController & Service class as well.
I get this exception:
Caused by BeanDefinitionOverrideException: Invalid bean definition with name 'elementController' defined in class path resource [ui/v2/web/ElementControllerSite1IT$TestSite1Config.class]: Cannot register bean definition [Root bean: class [null]; ... defined in class path resource [ui/v2/web/ElementControllerSite1ITConfig.class] for bean 'elementController': There is already [Generic bean: class [ui.v2.web.ElementController]; .. defined in file [...ui/v2/web/ElementController.class]] bound.
I didn't write the tests, it's code that I've inherited, in a code base that I'm just getting spooled up on.
You could try #TestPropertySource(properties ="..." :
#ExtendWith(SpringExtension.class)
#WebMvcTest(value = ElementController.class, secure = false)
#ContextConfiguration(classes = TestSite1Config.class)
#TestPropertySource(properties = {"spring.main.allow-bean-definition-overriding=true", "local.server.port=7777"})
public class ElementControllerSite1IT {
...
}
Add spring.main.allow-bean-definition-overriding=true to application.properties
Got it working with this: (for anyone who stumbles upon this question)
#ExtendWith(SpringExtension.class)
#AutoConfigureMockMvc
#WebMvcTest
#ContextConfiguration(classes = {ElementController.class,TestSite1Config.class})
public class ElementControllerSite1IT {
#Autowired
private MockMvc mvc;
...
#Configruation
public static class TestSite1Config {
#Bean
#Primary
public ElementControllerProperties elementControllerProperties() { return ... }
}
...
}

Spring Actuator - How to exclude HealthEndpoint from autowiring in test

I am trying to run a test but I got an exception when I try to run it Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.boot.actuate.endpoint.HealthEndpoint' available:
I have two packages com.test.data and com.test.health in my main folder. My main Application class is in com.test.data. In com.test.health I have one class with name StartupHousekeeper implements ApplicationListener<ApplicationReadyEvent> and autowired HealthEndpoint there as below
#Component
public class StartupHousekeeper implements ApplicationListener<ApplicationReadyEvent> {
#Autowired
private HealthEndpoint healthEndpoint;
}
In test I have ControllerIntegrationTest which is config class and code is below. Even though I did not add com.test.health package it is still throwing NoSuchBeanDefinitionException.
#Profile("controller-integration-test")
#ComponentScan(basePackages = {"com.test.data"})
#Configuration
public class ControllerIntegrationTest {
}
My actual test class is below
#TestExecutionListeners(MockitoTestExecutionListener.class)
#ActiveProfiles({"controller-integration-test"})
#ContextConfiguration(classes = ControllerIntegrationTest.class)
#WebMvcTest(value = AdminUserController.class, secure = false, excludeAutoConfiguration = {HealthIndicatorAutoConfiguration.class, HibernateJpaAutoConfiguration.class, FlywayAutoConfiguration.class, DataSourceAutoConfiguration.class})
public class AdminUserControllerTest extends AbstractTestNGSpringContextTests implements TestConstants {}
When I try to run it org.springframework.test.context.testng.AbstractTestNGSpringContextTests#springTestContextPrepareTestInstance failed to run due to above mentioned exception

Inject #PersistenceContext in test unit for spring

I have problem when injecting entityManager in my test class. I think that this is because i can't load my spring context in my test class.
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'noteDeFraisDAO': Injection of persistence dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'javax.persistence.EntityManagerFactory' available
this is my test class
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {NoteDeFraisTestConfig.class})
#Transactional
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
public class NoteDeFraisDAOIT
{
#Autowired
private NoteDeFraisDAO noteDeFraisDAO;
#Test
public void myTest()
{
}
}
And this is the configuration for the test I know that when I use new there will be no inject of entitiesManager define in the dao but I don't know what should I do.
#Configuration
public class NoteDeFraisTestConfig {
#Bean
NoteDeFraisDAO noteDeFraisDAO()
{
return new NoteDeFraisDAO();
}
}
I have tried to set my ContextConfiguration to my applicationContext but it didn't work I think that it is because the directory WEB-INF doesn't belong to the classpath. How can I fix this??
This is the structure of my project
thanks.
Update
this is my final test class
#WebAppConfiguration
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({"file:web/WEB-INF/applicationContext.xml", "file:web/WEB-INF/db-config.xml","file:web/WEB-INF/dispatcher-servlet.xml","file:web/WEB-INF/security-config.xml"})
#Transactional
public class NoteDeFraisDAOIT
{
#Autowired
private NoteDeFraisDAO noteDeFraisDAO;
#Test
public void myTest()
{
}
}
Yep, the problem is that the ApplicationContext loaded for your test does not contain the LocalContainerEntityManagerFactoryBean. Assuming that's declared properly in applicationContext.xml, the linked solution below will help.
I have tried to set my ContextConfiguration to my applicationContext but it didn't work I think that it is because the directory WEB-INF doesn't belong to the classpath. How can I fix this??
That's covered here: Location of spring-context.xml

#Autowired bean is null in Test Listener class

This question was asked before Using Autowired in a TestExecutionListener class for BeforeClass junit however it wasn't answered. I am facing the same problem but haven't figured out the solution
Example: I am getting null mapper.
public class CustomExecutionListener extends AbstractTestExecutionListener {
#Autowired
private Mapper mapper;
#Override
public void beforeTestClass(TestContext testContext) {}
... some code...
}
Test Class: Note: AppConfig contains the Mapper Bean defined.
#RunWith(SpringJUnit4ClassRunner.class)
#TestExecutionListeners(listeners = {DependencyInjectionTestExecutionListener.class, CustomExecutionListener.class})
#ContextConfiguration(classes = {AppConfig.class})
public class AccountControllerTest {
....
}
Dependency injection is not supported for TestExecutionListener instances.
Dependency injection is only supported for test instances.
Thus, if your CustomExecutionListener needs to access a bean from the ApplicationContext, it will have to look it up manually -- for example, like this:
public void beforeTestClass(TestContext testContext) {
Mapper mapper = testContext.getApplicationContext().getBean(Mapper.class);
// ... some code...
}
Regards,
Sam (author of the Spring TestContext Framework)
You can also try this: Mapper mapper = Mappers.getMapper(Mapper.class);

Resources