Service was not introduced in Spring with spring -test-mvc controller test

I am trying to create a unit / integration test suite for a Restful API Server created using Spring MVC 3.1.1.

I am trying to use Spring-test-mvc .

I am relatively new to Spring and therefore spring -test-mvc.

I will include the relevant sections of my code so that you can feel how I structured it:

PurchaseController:

@Controller public class PurchaseController { @Autowired private IPurchaseService purchaseService; @RequestMapping(value = "purchases", method = RequestMethod.GET) @ResponseBody public final List<Purchase> getAll() { return purchaseService.getAll(); } } 

PurchaseService:

 @Service public class PurchaseService implements IPurchaseService { @Autowired private IPurchaseDAO purchaseDAO; public PurchaseService() { } @Transactional public List<Purchase> getAll() { return purchaseDAO.findAll(); } } 

PurchaseDAO:

 @Repository public class PurchaseDAO extends AbstractJpaDAO<Purchase> implements IPurchaseDAO { @PersistenceContext EntityManager entityManager; public PurchaseDAO() { setClazz(Purchase.class); } } 

AbstractJpaDAO:

 public abstract class AbstractJpaDAO<T extends Serializable> implements IAbstractJpaDAO<T> { private Class<T> clazz; @PersistenceContext EntityManager entityManager; public void setClazz(final Class<T> clazzToSet) { this.clazz = clazzToSet; } public List<T> findAll() { return entityManager.createQuery("from " + clazz.getName()) .getResultList(); } } 

Here is my controller test:

 public class PurchaseControllerTest extends AbstractControllerTest { @Autowired private IPurchaseService purchaseService; @Autowired private PurchaseController purchaseController; private MockMvc mockMvc; @Before public void setup() { // Test Purchase Purchase purchase = new Purchase(); purchase.setPan(5412311111111121l); purchase.setCvc((short) 122); purchase.setExpiry("1215"); purchase.setMerchantName("TestMerchant"); purchase.setMerchantType("Airline"); purchase.setTransactionAmount(new BigDecimal("300.99")); mockMvc = MockMvcBuilders.standaloneSetup(purchaseController).build(); purchaseService.addPurchase(purchase); } @Test public void testGetAll() throws Exception { this.mockMvc .perform(get("/purchase").accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(content().type(MediaType.APPLICATION_JSON)); } } 

AbstractControllerTest:

 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {ControllerTestConfig.class}, loader=AnnotationConfigContextLoader.class) @ActiveProfiles("test") public class AbstractControllerTest { } 

ControllerTestConfig:

 @Configuration @Profile("test") public class ControllerTestConfig { @Bean public PurchaseService purchaseService() { return new PurchaseService(); } @Bean public PurchaseDAO purchaseDAO() { return new PurchaseDAO(); } @Bean public EntityManagerFactory entityManager() { return new LocalEntityManagerFactoryBean().getObject(); } } 



I get the following error while running my test through Eclipse JUnit:

 2012-07-08 16:16:00,017 TRACE [main] oscsGenericApplicationContext [AbstractApplicationContext.java:322] Publishing event in org.springframework.context.support.GenericApplicationContext@42 b307f0: org.springframework.context.event.ContextRefreshedEvent[sourc e=org.springframework.context.support.GenericApplicationContext@ 42b307f0: startup date [Sun Jul 08 16:15:59 IST 2012]; root of context hierarchy] 2012-07-08 16:16:00,018 DEBUG [main] ostcTestContext [TestContext.java:150] Storing ApplicationContext for test class [class com.app.controller.PurchaseControllerTest] in cache under key [[ MergedContextConfiguration@2f8a49e0 testClass = PurchaseControllerTest, locations = '{}', classes = '{class com.app.spring.testing.ControllerTestConfig}', activeProfiles = '{test}', contextLoader = 'org.springframework.test.context.support.AnnotationConfigContextLoader']]. 2012-07-08 16:16:00,019 TRACE [main] osbCachedIntrospectionResults [CachedIntrospectionResults.java:222] Getting BeanInfo for class [com.app.controller.PurchaseControllerTest] 2012-07-08 16:16:00,022 TRACE [main] osbCachedIntrospectionResults [CachedIntrospectionResults.java:238] Caching PropertyDescriptors for class [com.app.controller.PurchaseControllerTest] 2012-07-08 16:16:00,022 TRACE [main] osbCachedIntrospectionResults [CachedIntrospectionResults.java:250] Found bean property 'class' of type [java.lang.Class] 2012-07-08 16:16:00,023 TRACE [main] osbCachedIntrospectionResults [CachedIntrospectionResults.java:250] Found bean property 'mockMvc' of type [org.springframework.test.web.server.MockMvc] 2012-07-08 16:16:00,026 DEBUG [main] osbfaInjectionMetadata [InjectionMetadata.java:60] Found injected element on class [com.app.controller.PurchaseControllerTest]: AutowiredFieldElement for private com.app.service.IPurchaseService com.app.controller.PurchaseControllerTest.purchaseService 2012-07-08 16:16:00,026 DEBUG [main] osbfaInjectionMetadata [InjectionMetadata.java:60] Found injected element on class [com.app.controller.PurchaseControllerTest]: AutowiredFieldElement for private com.app.controller.PurchaseController com.app.controller.PurchaseControllerTest.purchaseController 2012-07-08 16:16:00,027 DEBUG [main] osbfaInjectionMetadata [InjectionMetadata.java:85] Processing injected method of bean 'com.app.controller.PurchaseControllerTest': AutowiredFieldElement for private com.app.service.IPurchaseService com.app.controller.PurchaseControllerTest.purchaseService 2012-07-08 16:16:00,034 ERROR [main] ostcTestContextManager [TestContextManager.java:324] Caught exception while allowing TestExecutionListener [org.springframewor k.test.context.support.DependencyInjectionTestExecutionListener@ 403ef810] to prepare test instance [ com.app.controller.PurchaseControllerTest@656546ef ] org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.app.controller.PurchaseControllerTest': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.app.service.IPurchaseService com.app.controller.PurchaseControllerTest.purchaseService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.app.service.IPurchaseService] 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:287) ~[spring-beans-3.1.1.RELEASE.jar:3.1.1.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1106) ~[spring-beans-3.1.1.RELEASE.jar:3.1.1.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:374) ~[spring-beans-3.1.1.RELEASE.jar:3.1.1.RELEASE] at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:110) ~[spring-test-3.1.1.RELEASE.jar:3.1.1.RELEASE] at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75) ~[spring-test-3.1.1.RELEASE.jar:3.1.1.RELEASE] 

Any ideas on why my PurchaseService is not being created and introduced?


UPDATE

So, I added my Bean shopping service to ControllerTestConfig ... now I get a message about my DAO purchase.

How can I add this to my ControllerTestConfig? Do I need to embed it inside the purchase bean?

 2012-07-08 18:30:23,029 ERROR [main] ostcTestContextManager [TestContextManager.java:324] Caught exception while allowing TestExecutionListener [org.springframewor k.test.context.support.DependencyInjectionTestExecutionListener@ 56da6bf4] to prepare test instance [ com.app.controller.PurchaseControllerTest@df4cbee ] java.lang.IllegalStateException: Failed to load ApplicationContext at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:157) ~[spring-test-3.1.1.RELEASE.jar:3.1.1.RELEASE] at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109) ~[spring-test-3.1.1.RELEASE.jar:3.1.1.RELEASE] at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75) ~[spring-test-3.1.1.RELEASE.jar:3.1.1.RELEASE] at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:321) ~[spring-test-3.1.1.RELEASE.jar:3.1.1.RELEASE] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211) [spring-test-3.1.1.RELEASE.jar:3.1.1.RELEASE] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288) [spring-test-3.1.1.RELEASE.jar:3.1.1.RELEASE] at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) [junit-4.8.1.jar:na] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:290) [spring-test-3.1.1.RELEASE.jar:3.1.1.RELEASE] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231) [spring-test-3.1.1.RELEASE.jar:3.1.1.RELEASE] at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) [junit-4.8.1.jar:na] at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193) [junit-4.8.1.jar:na] at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) [junit-4.8.1.jar:na] at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) [junit-4.8.1.jar:na] at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) [junit-4.8.1.jar:na] at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) [junit-4.8.1.jar:na] at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) [spring-test-3.1.1.RELEASE.jar:3.1.1.RELEASE] at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71) [spring-test-3.1.1.RELEASE.jar:3.1.1.RELEASE] at org.junit.runners.ParentRunner.run(ParentRunner.java:236) [junit-4.8.1.jar:na] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174) [spring-test-3.1.1.RELEASE.jar:3.1.1.RELEASE] at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) [.cp/:na] at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) [.cp/:na] at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) [.cp/:na] at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) [.cp/:na] at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) [.cp/:na] at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) [.cp/:na] Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'purchaseService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.app.persistence.dao.IPurchaseDAO com.app.service.impl.PurchaseService.purchaseDAO; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'purchaseDAO': Injection of persistence dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [javax.persistence.EntityManagerFactory] is defined: expected single bean but found 0 at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:287) ~[spring-beans-3.1.1.RELEASE.jar:3.1.1.RELEASE] 

I added PurchaseDAO Bean to ControllerTestConfig.

Update 2

So now I get a null pointer exception after adding An EntityManagerFactory Bean to my ControllerTestConfig!

 java.lang.IllegalStateException: Failed to load ApplicationContext at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:157) ~[spring-test-3.1.1.RELEASE.jar:3.1.1.RELEASE] at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109) ~[spring-test-3.1.1.RELEASE.jar:3.1.1.RELEASE] at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75) ~[spring-test-3.1.1.RELEASE.jar:3.1.1.RELEASE] at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:321) ~[spring-test-3.1.1.RELEASE.jar:3.1.1.RELEASE] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211) [spring-test-3.1.1.RELEASE.jar:3.1.1.RELEASE] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288) [spring-test-3.1.1.RELEASE.jar:3.1.1.RELEASE] at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) [junit-4.8.1.jar:na] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:290) [spring-test-3.1.1.RELEASE.jar:3.1.1.RELEASE] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231) [spring-test-3.1.1.RELEASE.jar:3.1.1.RELEASE] at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) [junit-4.8.1.jar:na] at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193) [junit-4.8.1.jar:na] at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) [junit-4.8.1.jar:na] at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) [junit-4.8.1.jar:na] at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) [junit-4.8.1.jar:na] at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) [junit-4.8.1.jar:na] at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) [spring-test-3.1.1.RELEASE.jar:3.1.1.RELEASE] at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71) [spring-test-3.1.1.RELEASE.jar:3.1.1.RELEASE] at org.junit.runners.ParentRunner.run(ParentRunner.java:236) [junit-4.8.1.jar:na] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174) [spring-test-3.1.1.RELEASE.jar:3.1.1.RELEASE] at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) [.cp/:na] at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) [.cp/:na] at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) [.cp/:na] at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) [.cp/:na] at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) [.cp/:na] at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) [.cp/:na] Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'purchaseService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.app.persistence.dao.IPurchaseDAO com.app.service.impl.PurchaseService.purchaseDAO; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'purchaseDAO': Injection of persistence dependencies failed; nested exception is java.lang.NullPointerException at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:287) ~[spring-beans-3.1.1.RELEASE.jar:3.1.1.RELEASE] 

Any ideas? Thanks

+6
source share
4 answers

This will not work since spring -test-mvc does not select the context configuration from ContextConfiguration Junit, you can do it instead (if your beans service is loading somewhere through the ControllerTestConfig configuration)

 MockMvcBuilders.annotationConfigSetup(ControllerTestConfig.class).build().perform(get("/purchase").accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(content().type(MediaType.APPLICATION_JSON)); 
+2
source

You will need to add some @Bean to your test @Configuration profile.

You didnโ€™t have them before, but from your update I see that you have your PurchaseService . Well, your PurchaseService has @Autowired PurchaseDao , which should also be added to your test profile.

Try adding this to ControllerTestConfig :

 @Bean public IPurchaseDao purchaseDao() { return new PurchaseDao(); } 

Your PurchaseDao uses an EntityManager , which can also be added to your ControllerTestConfig class. (I am not very good at this part, so I canโ€™t say that ...)

+1
source

Given that you are using @ContextConfiguration (TestContext framework) to load the Spring configuration, I assume that you want to run an integration test that involves loading your controllers, services and repositories from the Spring configuration. However, you are using the standaloneSetup method for MockMvcBuilders, which is intended for more targeted unit tests intended primarily for controllers (usually both services and repositories).

Consider using the WebApplicationContextSetup method for MockMvcBuilders. Here is an example .

+1
source

I donโ€™t know if this will help you, but in order to inherit the context from @ContextConfiguration , you need to auto-install it in the test class, after which you can set it as the parent context of ControllerTestConfig.class .

In my configuration, I have separated the persistence configuration that will be loaded from @ContextConfiguration and the MVC configuration that will be loaded from annotationConfigSetup .

 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(loader=AnnotationConfigContextLoader.class, classes={PersistenceJPAConfig.class}) public class PurchaseControllerTest { @Autowired private ApplicationContext ac; private PurchaseService service; private MockMvc mvc; @Before public void before() { mvc = annotationConfigSetup(ControllerTestConfig.class). setParentContext(ac).build(); service = ac.getBean(PurchaseService.class); } } 

Since annotationConfigSetup does not know that you have an external configuration, you must specify this directly by setting its parent context.

You cannot enter your services inside your test class, but you can restore it from the context, as well as add it to your controllers. Well, you can insert, but it will not be the same service that will be introduced into your controllers. By getting this from the context that you pass as a parent, you guarantee that they are the same. Since I am mocking my services, this is important.

0
source

Source: https://habr.com/ru/post/919976/


All Articles