0
votes

I faced problem that I cannot solve by myself. I guess solution might be obvious when checked by someone with Spring experience.

I have a very simple repository:

interface MovieRepository extends Repository<Movie, Long> {
Movie findMovieById(Long id);
void save(Movie movie);
}

And facade to perform some actions:

@AllArgsConstructor
public class MovieFacade {

private MovieRepository movieRepository;
private MovieCreator movieCreator;

public MovieDto getMovieById(Long id){
    Optional<Movie> movie = Optional.ofNullable(movieRepository.findMovieById(id));
    return movie.isPresent() ? movie.get().toDto() : null;
}

Configuration class looks like this:

@Configuration
class MovieConfiguration {

@Bean
MovieFacade movieFacade(MovieRepository repository, MovieCreator movieCreator){
    return new MovieFacade(repository, movieCreator);
}

@Bean
MovieCreator movieCreator(){
    return new MovieCreator();
}

I wanted to create some tests and this fails every time I try to run them:

@RunWith(SpringJUnit4ClassRunner.class)
public class MovieFacadeTest {

@Autowired
MovieFacade movieFacade;

@Test
public void dependecyWorks(){
    assertNotNull(movieFacade);
}

This is the error I get:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.example.demo.movie.domain.MovieFacadeTest': Unsatisfied dependency expressed through field 'movieFacade'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.demo.movie.domain.MovieFacade' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:386) at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:118) at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83) at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 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.run(ParentRunner.java:363) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140) Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.demo.movie.domain.MovieFacade' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

As far as I'm concerned object movieFacade should be created in MovieConfiguration and then injected into movieFacade in test class. For some reason it simply does not happen. I would appreciate any help or hint that may lead to solving this problem.

2

2 Answers

0
votes

I think you need to annotate your test class with @ContextConfiguration and give the class reference of your configuration class. While running JUNIT it will not automatically create Spring context where you have defined MovieFacade bean. You need to give that reference in the JUnit class.

0
votes

Read the stacktrace closely it says:

 nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.demo.movie.domain.MovieFacade' available: expected at least 1 bean which qualifies as autowire candidate. 

You haven't annotated your MovieFacade with @Service or @Component so its not getting picked up by the application context. Also, You should use @ComponentScan annotation above your configuration if MovieFacade isen't in the same package as you configuration class. @ComponentScan() can take package names and class names as arguments. If MovieFacade is in the same package as the configuration file then @ComponentScan isn't necessary because a configuration class scans its own package for components by default.

Hope this helps.

EDIT: Also, MovieRepository should have the annotation @Repository