Reputation: 1143
I am new to Spring MVC and JUnit. Basically I want to autowire the service class and this class should be loaded in spring context.
Service
@Service public class FundService { @Autowired FundDAO fundDAO; /** * @return */ public List getFundDetails(String productId) { return fundDAO.getFundDetails(productId); } }
application-context
<beans>
<mvc:annotation-driven />
<context:component-scan base-package="com.test.*" />
</beans>
Junit class
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"classpath*:/WEB-INF/application-context.xml"}) public class CompensationServiceTest { @Autowired private FundService fundService; @Test public void verifyGetCompensationList() { System.out.println(fundService == null); } }
While executing the test I am getting following exception trace
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.test.admin.service.CompensationServiceTest': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.test.admin.service.FundService com.test.admin.service.CompensationServiceTest.fundService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.test.admin.service.FundService] 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.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:286) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1064) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:374) at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:110) at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75) at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:333) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:220) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:301) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:303) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) 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:236) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.test.admin.service.FundService com.test.admin.service.CompensationServiceTest.fundService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.test.admin.service.FundService] 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.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:507) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:84) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:283) ... 26 more Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.test.admin.service.FundService] 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:903) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:772) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:686) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:478) ... 28 more
Upvotes: 1
Views: 12485
Reputation: 1475
In my case I had nested classed / param'ed tests:
BEFORE
@RunWith(Enclosed.class)
@ContextConfiguration(classes = {TestX.class})
public class SimpleTest {
...
@RunWith(Parameterized.class)
public static class SimpleCheckAddTest{
.....
}
@RunWith(Parameterized.class)
public static class SimpleCheckRemoveTest{
.....
}
}
and got: <.....Unsatisfied dependency expressed through field......> exception like.
AFTER
@RunWith(Enclosed.class)
public class SimpleTest {
...
@RunWith(Parameterized.class)
@ContextConfiguration(classes = {TestX.class})
public static class SimpleCheckAddTest{
.....
}
@RunWith(Parameterized.class)
@ContextConfiguration(classes = {TestX.class})
public static class SimpleCheckRemoveTest{
.....
}
}
Upvotes: 0
Reputation: 2280
There are two options:
If you use @Autowire
it means you're creating an application context for your tests, there are several steps to achieve this; Instead of telling you how, I'd like to tell you about the right approach.
Since you're talking about unit tests it means the class you're testing is isolated and the injected dependencies have to be mocks, an example next:
The class:
@RestController
@RequestMapping(value = "/")
public class CatalogRest {
@Autowired
private CatalogService catalogService;
@Autowired
private LoggedUser loggedUser;
@RequestMapping(value = GET_VIEW_TYPE, method = POST)
public ResponseEntity<List<ViewType>> getViewType() {
List<ViewType> viewTypes = catalogService.getViewType(loggedUser.getUserId());
return new ResponseEntity<List<ViewType>>(viewTypes, HttpStatus.OK);
}
Now the test:
@RunWith(MockitoJUnitRunner.class)
public class CatalogRestTest {
@InjectMocks
private CatalogRest subject;
@Mock
private CatalogService catalogService;
@Mock
private LoggedUser loggedUser;
@Before
public void init() {
MockitoAnnotations.initMocks(this);
}
@Test
public void classAndItsMethodsHaveRequiredAnnotations() throws Exception {
assertTrue(subject.getClass().isAnnotationPresent(RestController.class));
assertTrue(subject.getClass().isAnnotationPresent(RequestMapping.class));
Method getViewTypeMethod = subject.getClass().getMethod("getViewType");
getViewTypeMethod.isAnnotationPresent(RequestMapping.class);
}
@Test
public void getViewType_whenInvoked_returnsAListOfViewTypes() throws Exception {
List<ViewType> viewTypes = Arrays.asList(new ViewType());
when(loggedUser.getUserId()).thenReturn("fake user");
when(catalogService.getViewType(eq("fake user"))).thenReturn(viewTypes);
ResponseEntity<List<ViewType>> result = subject.getViewType();
assertNotNull(result);
assertNotNull(result.getBody());
assertTrue(result.getBody().size() == 1);
verify(catalogService, times(1)).getViewType(eq("fake user"));
}
Do not attempt to use spring for unit testing, it only should be used for integration testing
.
Upvotes: 2
Reputation: 643
Can you post the code where you do your bean configuration. The problem here is that Spring is trying to find a concrete class to wire for
@Autowired
private FundService fundService;
You need to specify the bean Spring should inject in your configuration. For example, doing it in XML you would say:
<beans>
<mvc:annotation-driven />
<context:component-scan base-package="com.test.*" />
<!-- Assuming FundServiceImpl is a class that implement FundService -->
<bean id="fundService" class="com.test.admin.service.FundServiceImpl"/>
</beans>
Upvotes: 0
Reputation: 31197
First of all, the WEB-INF
folder should never be in the classpath; it should be in the file system of the project. So if you use the Maven project structure, that folder would be located relative to the root of your project (i.e., src/main/webapp/WEB-INF
). In that case you would want to declare an XML configuration file in that folder as a file system resource like this:
@ContextConfiguration("file:src/main/webapp/WEB-INF/application-context.xml")
Secondly, if this is a test configuration file, you should not store it under WEB-INF
. Instead, you should store it in the classpath. Following the Maven project structure, this would be src/test/resources/application-context.xml
, in which case you would use the following declaration in your test:
@ContextConfiguration("/application-context.xml")
or
@ContextConfiguration("classpath:application-context.xml")
... whichever your prefer, but note that they are equivalent.
Regards and thanks,
Sam
Upvotes: 2
Reputation: 24124
You have to qualify the Service class with "@Component" annotation for it to be picked during component scan, right?
Upvotes: 0