Using Spring components in tests - java

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 {
...

Related

Autowiring Spring services into JUnit tests

Following is the service.
#Service
public class MyService {
public List<Integer> getIds(Filter filter){
// Method body
}
}
And a configuration class.
#Configuration
public static class MyApplicationContext {
#Bean
public Filter filter(ApplicationContext context) {
return new Filter();
}
}
The desired goal is a unit test to confirm getIds() returns the correct result.
See the JUnit test below.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes=MyApplicationContext.class,
loader=AnnotationConfigContextLoader.class)
public class AppTest
{
#Autowired
Filter filter;
#Autowired
MyService service;
}
The compiler finds the correct bean for the Filter class but throws a BeanCreationException: Could not autowire field exception for the service variable. I've tried adding the service class to the ContextConfiguration classes attribute but that results in a IllegalStateException: Failed to load ApplicationContext exception.
How can I add MyService to ContextConfiguration?
Add the following annotation to MyApplicationContext for the service to be scanned #ComponentScan("myservice.package.name")
Add these two annotations to the test class AppTest, like in the following example:
#RunWith(SpringRunner.class )
#SpringBootTest
public class ProtocolTransactionServiceTest {
#Autowired
private ProtocolTransactionService protocolTransactionService;
}
#SpringBootTest loads the whole context.

Spring Context Initialization fails

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
}

#Autowired dependency injection not occurring in junit test

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);
}
}

Resolve Spring #Value expression in JUnit tests

Here's a snippet of a Spring bean:
#Component
public class Bean {
#Value("${bean.timeout:60}")
private Integer timeout;
// ...
}
Now I want to test this bean with a JUnit test. I'm therefore using the SpringJUnit4ClassRunner and the ContextConfiguration annotation.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class BeanTest {
#Autowired
private Bean bean;
// tests ...
#Configuration
public static class SpringConfiguration {
#Bean
public Bean bean() {
return new Bean();
}
}
}
Unfortunately the SpringJUnit4ClassRunner can't resolve the #Value expression, even though a default value is supplied (a NumberFormatException is thrown). It seems that the runner isn't even able to parse the expression.
Is something missing in my test?
Your test #Configuration class is missing an instance of PropertyPlaceholderConfigurer and that's why Spring does not know how to resolve those expressions; add a bean like the following to your SpringConfiguration class
#org.springframework.context.annotation.Bean
public static PropertyPlaceholderConfigurer propertyPlaceholderConfigurer() {
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.setIgnoreResourceNotFound(true);
return ppc;
}
and move it to a separate class and use
#ContextConfiguration(classes=SpringConfiguration.class)
to be more specific when running your test.

Context initialization issue for controller Unit testing with Spring 3.2 and Mockito

I'm trying to provide a clean Unit Test for a Controller of mine. This Controller has a Service as dependency and this Serviceh has a Datasource as dependency.
The test looks like this:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration
public class ContentActionWebServiceControllerTest {
#Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
#Autowired
private MyService myService;
#Test
public void getRequestActionList() throws Exception {
when(...)
perform(...);
verify(...);
}
#Configuration
#ImportResource("...")
static class MyTestConfiguration {
#Bean
public MyService myService() {
return Mockito.mock(MyService.class);
}
}
}
And the MyService is something like
#Service
public class MyService {
#Autowired
private MyDataSource myDatasource;
...
}
Because MyService as an Autowired property MyDataSource, the context isn't initialized because it doesn't find any MyDataSource type for satisfying the #Autowired annotation of MyService. But why does it ever try to resolve this annotation? Is this is a mock?
Mockito does use cglib to create a new child class of MyService (and override all methods with mock methods).
But still, the dependencies of the parent will be injected, because this is how Spring does it's job:
if you have a parent class with some #Autowired fields, and a child class that inherits from this parent class, then Spring will inject the #Autowired fields of the parent when instantiating the child. I guess it's the same behavior in your case.
If you use an interface for MyService, then your problem will be solved.
If it's supposed to be a unit test (and not an integration test) you don't even need to use Spring, you can do it all with JUnit+Mockito. Rather than #Autowireing dependencies from Spring context, you can simply create mocks of the support objects (via #Mock) and inject them to the testee (via #InjectMocks). I believe your code could be simplified to something (conceptually) like this:
#RunWith(MockitoJUnitRunner.class)
public class ContentActionWebServiceControllerTest {
#Mock
private Service mockServiceUsedByController;
#InjectMocks
private YourController testee;
#Test
public void getRequestActionList() throws Exception {
assertFalse(testee.getRequestActionList().isEmpty());
// etc.
}
}

Categories