I'm using Spring Boot to bootstrap a spring-data-neo4j application. My unit tests (with no dependencies injected) run fine, but when I try to run an integration test with an #Autowired dependency on a #Service-annotated class, it's failing on a NoSuchBeanDefinitionException.
It seems like the context isn't being loaded in the unit test for some reason, but I've annotated the test with #SpringApplicationConfiguration(classes = AppConfig.class) - is there something else I need to do here?
Configuration class
#Configuration
#EnableAutoConfiguration
#ComponentScan(basePackages = "net.foo.bar")
#EnableNeo4jRepositories(basePackages = "net.foo.bar.repo")
public class AppConfig extends Neo4jConfiguration {
public AppConfig() {
setBasePackage("net.foo.bar");
}
#Bean(destroyMethod = "shutdown")
#Scope(BeanDefinition.SCOPE_SINGLETON)
public GraphDatabaseService graphDatabaseService() {
return new GraphDatabaseFactory().newEmbeddedDatabase(filePath);
}
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(AppConfig.class, args);
}
}
Service class:
package net.foo.bar.core.service
#Service
public class PostService implements EntityService<PostDAO,Post> {
#Autowired
Neo4jTemplate template;
//...
//don't think anything else here is relevant
}
Test class:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = AppConfig.class)
public class PostTests {
#Autowired
PostService postService;
#Test
public void someTest(){
postService.doSomething();
//...
}
}
Stack trace:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'net.foo.bar.PostTests': ....
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [net.foo.bar.core.service.PostService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1103)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:963)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:858)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:480)
... 31 common frames omitted
Update:
As a workaround, rather than autowiring my service directly, I tried autowiring a reference to the ApplicationContext and instantiating my service through a call to getBeanOfType() in my setUp() method:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Epublic.class)
public class PostTests {
#Autowired
ApplicationContext ctx;
PostService service;
#Before
public void setUp() {
service = ctx.getBean("postServiceImpl", PostService.class);
}
}
This is working, but I feel like I'm hitting the target but missing the point here...
You don't have basePackages for #ComponentScan. You have only for NeojConfiguration
#Configuration
#EnableAutoConfiguration
#ComponentScan(basePackages = { "net.foo.bar" })
#EnableNeo4jRepositories(basePackages = "net.foo.bar.repo")
public class AppConfig extends Neo4jConfiguration {
public AppConfig() {
setBasePackage("net.foo.bar");
}
#Bean(destroyMethod = "shutdown")
#Scope(BeanDefinition.SCOPE_SINGLETON)
public GraphDatabaseService graphDatabaseService() {
return new GraphDatabaseFactory().newEmbeddedDatabase(filePath);
}
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(AppConfig.class, args);
}
}
Related
I have two #Configuration classes. I need a bean from one configuration class to another. I have autowired the configuration 1 into 2. All works fine. When executing the unit testing, am getting the below exception.
setUpContext(com.trafigura.titan.framework.services.messaging.loader.SpringLoadTest)
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.xxx.MessagingServicesConfig': Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.xxx.EMSJMSConfig com.xxx.MessagingServicesConfig.emsJmsConfig;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type[com.xxx.EMSJMSConfig] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Is there anything I need to do additionally to make this working?
Below is the setup for testing.
#Configuration
#Import({MessagingServicesConfig.class,...,EMSJMSConfig.class
})
public class MessagingConfig {}
#Profile("EMS-MESSAGING")
#Configuration
public class EMSJMSConfig {
#Bean
public javax.jms.ConnectionFactory jmsSubscriberConnectionFactory() throws JMSException {
SingleConnectionFactory singleConnectionFactory = new SingleConnectionFactory(tibjmsConnectionFactory());
return singleConnectionFactory;
}
}
#Configuration
public class MessagingServicesConfig {
#Autowired
private EMSJMSConfig emsJmsConfig;
#Bean(destroyMethod = "shutdown")
public MessagingService messagingService() throws JMSException {
...
ConnectionFactory cf=emsJmsConfig.jmsSubscriberConnectionFactory(); // Getting NPE at this line.
}
}
and finally the test class,
public class MessagingServicesConfigTest {
private MessagingServicesConfig config;
private EMSJMSConfig emsJmsConfig;
#BeforeMethod
public void setUp() throws Exception {
config = new MessagingServicesConfig();
... //what needs to be done here to have the EMSJMSConfig
}
#Test
public void testBuildsCorrectService() throws JMSException {
MessagingService service = config.messagingService();
...
}
}
By calling new you're creating object yourself, Spring doesn't know anything about it.
Moreover, you should have a test configuration which will be aware of your beans.
Use an appropriate Runner to load SpringContext.
#ContextConfiguration(classes = TestConfig.class)
#RunWith(SpringRunner.class)
class Tests {
#Autowired // if needed
private MessagingServicesConfig config;
}
While in TestConfig you can create beans or import configuration from the Application:
#Configuration
#Import({MessagingServicesConfig.class})
public class TestConfig {}
#Configuration
#Import({EMSJMSConfig.class})
public class MessagingServicesConfig {}
Or you can refer to your config classes directly:
#ContextConfiguration(classes = {MessagingServicesConfig.class, EMSJMSConfig.class})
I am using JUnit tests with Spring configuration defined in a class annotated with #Configuration in my JUnit Test. The tests looks like this:
#ContextConfiguration(classes = MyConfiguration.class})
#RunWith(SpringJUnit4ClassRunner.class)
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class SomeIntegrationTest {
#Autowired
private MyConfiguration myConfiguration;
#Test
public void someTest() throws Exception {
myConfiguration.myBean();
}
}
In MyConfiguration, I would like to use Spring scope SimpleThreadScope:
#Configuration
public class MyConfiguration {
#Bean
#Scope("thread")
public MyBean myBean() {
return new MyBean();
}
}
When I run the test, the scope is not registered, though. I get
java.lang.IllegalStateException: Failed to load ApplicationContext
...
Caused by: java.lang.IllegalStateException: No Scope registered for scope 'thread'
I am aware how a custom scope can be registered programatically:
context.getBeanFactory().registerScope("thread", new SimpleThreadScope());
and I would like to avoid using XML Spring configuration.
Is there any way, how can I register the custom scope in the unit test?
Check this execution listener:
public class WebContextTestExecutionListener extends
AbstractTestExecutionListener {
#Override
public void prepareTestInstance(TestContext testContext) throws Exception {
if (testContext.getApplicationContext() instanceof GenericApplicationContext) {
GenericApplicationContext context = (GenericApplicationContext) testContext.getApplicationContext();
ConfigurableListableBeanFactory beanFactory = context
.getBeanFactory();
Scope requestScope = new SimpleThreadScope();
beanFactory.registerScope("request", requestScope);
Scope sessionScope = new SimpleThreadScope();
beanFactory.registerScope("session", sessionScope);
Scope threadScope= new SimpleThreadScope();
beanFactory.registerScope("thread", threadScope);
}
}
}
in the test you can put this
#ContextConfiguration(classes = MyConfiguration.class})
#RunWith(SpringJUnit4ClassRunner.class)
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
#TestExecutionListeners( { WebContextTestExecutionListener.class})
public class UserSpringIntegrationTest {
#Autowired
private UserBean userBean;
//All the test methods
}
I'm pretty much stucked and I hope you guys can help me out. Somehow I can't manage to get my spring context initialized.
I have these nice Bean Configuration classes:
#Configuration
public class CoreConfig {
#Bean
public TeamService createService(TeamPersistenceService teamPersistenceService) {
return new TeamEventHandler(teamPersistenceService);
}
}
And this one:
#Configuration
#EnableJpaRepositories(basePackages = "de.ktv.persistence.repository", //
includeFilters = #ComponentScan.Filter(value = { TeamsRepository.class }, type = FilterType.ASSIGNABLE_TYPE))
#EnableTransactionManagement
public class PersistenceConfig {
#Bean
public TeamPersistenceService createService(TeamsRepository repository) {
return new TeamPersistenceEventHandler(repository);
}
}
And in this test I want to use them:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { CoreConfig.class, PersistenceConfig.class })
public class CoreIntegrationTest {
#Autowired
TeamService teamService;
#Test
public void addNewTeamToTheSystem() {
//some test
}
The PersistenceConfig.class I am using in a different test and it works fine. But somehow here combined with CoreConfig.class it fails to initialize.
That is the error I get:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [de.ktv.core.services.TeamService] found for
dependency: expected at least 1 bean which qualifies as autowire
candidate for this dependency. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
I would really appreciate any help/hint.Thanks!
SpringContext cannot bind the #autowired if you don't indicate the same name. By default, the bean name will be the same as the method name, in this case, he is different, 2 options : change the method name or add attribut name !
Option 1
#Bean(name = "teamService")
public TeamService createService(TeamsRepository repository) {
return new TeamPersistenceEventHandler(repository);
}
Option 2
#Bean
public TeamService teamService(TeamsRepository repository) {
return new TeamPersistenceEventHandler(repository);
}
Enjoy \o/
#Configuration
public class CoreConfig {
#Autowired
private TeamPersistenceService teamPersistenceService;
#Bean
public TeamService teamService() {
return new TeamEventHandler(teamPersistenceService);
}
}
And this one:
#Configuration
#EnableJpaRepositories(basePackages = "de.ktv.persistence.repository", //
includeFilters = #ComponentScan.Filter(value = { TeamsRepository.class }, type = FilterType.ASSIGNABLE_TYPE))
#EnableTransactionManagement
public class PersistenceConfig {
#Autowired
private TeamsRepository repository:
#Bean
public TeamPersistenceService teamPersistenceService() {
return new TeamPersistenceEventHandler(repository);
}
}
And in this test I want to use them:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { CoreConfig.class, PersistenceConfig.class })
public class CoreIntegrationTest {
#Autowired
TeamService teamService;
#Test
public void addNewTeamToTheSystem() {
//some test
}
I have a class that looks roughly like this:
#Component
public class MyService {
private MyBean myBean;
#Autowired
public MyService(MyBean myBean) {
this.myBean = myBean;
}
}
I would like to test this class. It would be nice if I could get it to autowire in my tests using a test MyBean object. I tried doing this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader = AnnotationConfigContextLoader.class)
public class MyServiceTest {
#Autowired
MyService myService;
#Configuration
static class ContextConfiguration {
#Bean
public MyBean myBean() {
return createMock(myBean);
}
}
}
When I try to run my tests I get an error like:
Injection of autowired dependencies failed
No matching bean of type MyService found for dependency: expected at least one bean that is a candidate for this dependency.
How can I tell spring to look for my component so it knows how to autowire it?
Thanks.
You should enable component scan
#Configuration
#ComponentScan(basePackages = { MyServicePackage })
static class ContextConfiguration {
...
I am working on a spring boot based webservice with following structure:
Controller (REST) --> Services --> Repositories (as suggested in some tutorials).
My Database Connection (JPA/Hibernate/MySQL) is defined in a #Configuration class. (see below)
Now I'd like to write simple tests for methods in my Service classes, but I don't really understand how to load ApplicationContext into my test classes and how to mock the JPA / Repositories.
This is how far I came:
My service class
#Component
public class SessionService {
#Autowired
private SessionRepository sessionRepository;
public void MethodIWantToTest(int i){
};
[...]
}
My test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader = AnnotationConfigContextLoader.class)
public class SessionServiceTest {
#Configuration
static class ContextConfiguration {
#Bean
public SessionService sessionService() {
return new SessionService();
}
}
#Autowired
SessionService sessionService;
#Test
public void testMethod(){
[...]
}
}
But I get following exception:
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'sessionService': Injection of autowired
dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field: private com.myApp.SessionRepository
com.myApp.SessionService.sessionRepository; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type [com.myApp.SessionRepository] found for
dependency: expected at least 1 bean which qualifies as autowire
candidate for this dependency. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
For completeness: here's my #Configuration for jpa:
#Configuration
#EnableJpaRepositories(basePackages={"com.myApp.repositories"})
#EnableTransactionManagement
public class JpaConfig {
#Bean
public ComboPooledDataSource dataSource() throws PropertyVetoException, IOException {
...
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter) {
...
}
#Bean
public JpaVendorAdapter jpaVendorAdapter() {
...
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
...
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
...
}
}
use #SpringBootTest and #RunWith(SpringRunner.class) to load the context
#RunWith(SpringRunner.class)
#SpringBootTest
class Demo{
#Test
void contextLoad(){}
}
In your test Spring will use configuration only from inner ContextConfiguration class. This class describes your context. In this context you created only service bean and no repository. So the only bean that will be created is SessionService. You should add description of SessionRepository in inner ContextConfiguration. Your JpaConfig class will not be used in test class(you don't specify this), only in application.