[英]Spring Boot Data JPA cannot autowire repository interface in MockMVC test
I am using Spring Data JPA with Spring Boot and have a Mock MVC Test which results in the following stacktrace:我正在将 Spring Data JPA 与 Spring Boot 一起使用,并且有一个 Mock MVC 测试,它导致以下堆栈跟踪:
Parameter 1 of constructor in xyz.jacobclark.controllers.HomeController required a bean of type 'xyz.jacobclark.repositories.PageRepository' that could not be found.
Action:
Consider defining a bean of type 'xyz.jacobclark.repositories.PageRepository' in your configuration.
2017-02-26 18:29:11.350 ERROR 65426 --- [ main] o.s.test.context.TestContextManager : Caught exception while allowing TestExecutionListener [org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener@7219ec67] to prepare test instance [xyz.jacobclark.controllers.HomeControllerTest@1f0f1111]
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124) ~[spring-test-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83) ~[spring-test-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener.prepareTestInstance(SpringBootDependencyInjectionTestExecutionListener.java:47) ~[spring-boot-test-autoconfigure-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230) ~[spring-test-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228) [spring-test-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287) [spring-test-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) [junit-4.12.jar:4.12]
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289) [spring-test-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247) [spring-test-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94) [spring-test-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) [junit-4.12.jar:4.12]
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) [spring-test-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) [spring-test-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.junit.runners.ParentRunner.run(ParentRunner.java:363) [junit-4.12.jar:4.12]
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191) [spring-test-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.junit.runner.JUnitCore.run(JUnitCore.java:137) [junit-4.12.jar:4.12]
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117) [junit-rt.jar:na]
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42) [junit-rt.jar:na]
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262) [junit-rt.jar:na]
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84) [junit-rt.jar:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0]
at java.lang.reflect.Method.invoke(Method.java:483) ~[na:1.8.0]
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147) [idea_rt.jar:na]
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'homeController' defined in file [/Users/jacobclark/workspace/jacobclark.xyz/build/classes/main/xyz/jacobclark/controllers/HomeController.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'xyz.jacobclark.repositories.PageRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:749) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:189) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1193) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1095) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:866) ~[spring-context-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542) ~[spring-context-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:737) ~[spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:370) ~[spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:314) ~[spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:120) ~[spring-boot-test-1.5.1.RELEASE.jar:1.5.1.RELEASE]
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98) ~[spring-test-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116) ~[spring-test-4.3.6.RELEASE.jar:4.3.6.RELEASE]
... 28 common frames omitted
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'xyz.jacobclark.repositories.PageRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1486) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1104) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:835) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741) ~[spring-beans-4.3.6.RELEASE.jar:4.3.6.RELEASE]
Here is the actual repository:这是实际的存储库:
package xyz.jacobclark.repositories;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import xyz.jacobclark.models.entities.Page;
import java.util.List;
@Repository
public interface PageRepository extends CrudRepository<Page, String> {
List<Page> findById(String id);
List<Page> findByTitle(String titlex);
}
Whilst the controller looks like:虽然控制器看起来像:
package xyz.jacobclark.controllers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import xyz.jacobclark.adapters.GitHubAdapter;
import xyz.jacobclark.repositories.PageRepository;
import java.util.Map;
import java.util.concurrent.ExecutionException;
@Controller
public class HomeController {
PageRepository pageRepository;
private GitHubAdapter gitHubAdapter;
@Autowired
HomeController(GitHubAdapter gitHubAdapter, PageRepository pageRepository) {
this.gitHubAdapter = gitHubAdapter;
this.pageRepository = pageRepository;
}
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Map<String, Object> model) throws ExecutionException {
model.put("githubRepoCount", gitHubAdapter.getGitHubRepositoriesCount());
return "home";
}
}
And finally, the failing test:最后,失败的测试:
package xyz.jacobclark.controllers;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import xyz.jacobclark.adapters.GitHubAdapter;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@RunWith(SpringRunner.class)
@WebMvcTest(HomeController.class)
public class HomeControllerTest {
@Autowired
private MockMvc mvc;
@MockBean
private GitHubAdapter gitHubAdapter;
@Test
public void getOneRandomly() throws Exception {
when(gitHubAdapter.getGitHubRepositoriesCount()).thenReturn("42");
mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(view().name("home"))
.andExpect(model().attribute("githubRepoCount", "42"));
}
}
According to the docs the annotation @WebMvcTest
prevents components not relevant to MVC tests from being autowired, this includes @Repository
, which is why the above code does not work.根据文档,注释
@WebMvcTest
可防止自动装配与 MVC 测试无关的组件,这包括@Repository
,这就是上述代码不起作用的原因。
http://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTest.html http://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTest.html
The error says: No qualifying bean of type 'xyz.jacobclark.repositories.PageRepository'
错误说:
No qualifying bean of type 'xyz.jacobclark.repositories.PageRepository'
You have Mocked GitHubAdapter
but not provided any configuration to instantiate PageRepository
.您已经 Mocked
GitHubAdapter
但没有提供任何配置来实例化PageRepository
。
I would suggest 3 options:我会建议 3 个选项:
PageRepository
PageRepository
@ContextConfiguration
to instantiate the bean@ContextConfiguration
来实例化 bean@Autowired(required = false)
@Autowired(required = false)
Your Repository.您的存储库。
@Repository
public interface PageRepository extends CrudRepository<Page, String> {
List<Page> findById(String id);
List<Page> findByTitle(String titlex);
}
This @Repository(annotation) delete and move to your Implements(Implementation).这个@Repository(annotation) 删除并移动到你的Implements(Implementation)。 dao(interface) -> that annotation use DaoImpl class(implements).
dao(interface) -> 该注解使用DaoImpl类(实现)。
Sample entityManagerFactory示例 entityManagerFactory
<jpa:repositories base-package="xyz.jacobclark.repositories"></jpa:repositories>
Sample Repository示例存储库
Don`t use Annotation(@Repository).不要使用注释(@Repository)。 you use base-package in settings config.
您在设置配置中使用 base-package。
public interface AccountRepository extends PagingAndSortingRepository<Account, Integer>{
public Account findById(String id);
public List<Account> findByCompany(Company company);
}
Your controller您的控制器
@Controller
public class HomeController {
PageRepository pageRepository;
private GitHubAdapter gitHubAdapter;
@Autowired
HomeController(GitHubAdapter gitHubAdapter, PageRepository pageRepository) {
this.gitHubAdapter = gitHubAdapter;
this.pageRepository = pageRepository;
}
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Map<String, Object> model) throws ExecutionException {
model.put("githubRepoCount", gitHubAdapter.getGitHubRepositoriesCount());
return "home";
}
}
Sample controller样品控制器
You use service and dao in controller.您在控制器中使用service和dao 。 controller is gate.
控制器是门。 so implementation is just bean.
所以实现只是bean。 and i thinks you need to search DI and IOC.
我认为您需要搜索 DI 和 IOC。 i recommend to don`t use your mock test.
我建议不要使用你的模拟测试。 you use junit test.
你使用junit测试。 and you call unit(service and dao).
然后你打电话给单位(服务和道)。 this link : this Spring Tutorial and this jUnit + Spring Tutorial XD.
此链接:此 Spring 教程和此 jUnit + Spring 教程XD。
@RequestMapping(value = "/association")
@Controller
public class AssociationController {
@Autowired
private AssociationService associationService;
@Autowired
private AccountService accountService;
@Autowired
private CompanyService companyService;
@Autowired
private ProductService productService;
@RequestMapping(value = "/settings/company")
public ModelAndView showCompany(ModelAndView mav, HttpServletRequest req, Authentication auth) {
CustomUserDetail customUserDetail = (CustomUserDetail) auth.getPrincipal();
int associationIdx = customUserDetail.getAccount().getAssociation().getIdx();
Association association = associationService.findAssociationByIdx(associationIdx);
mav.addObject("association", association);
mav.setViewName("/association/association_settings_company");
return mav;
}
....
}
For me this is what worked:对我来说,这是有效的:
@MockBean
.@MockBean
Spring-Data 存储库接口,请使用@MockBean
。@Mock
(or with other standard methods)@Mock
(或其他标准方法)以标准方式@Mock
@WebMvcTest
annotation, i use @DataJpaTest
.@DataJpaTest
而不是@WebMvcTest
注释。 Not everyone needs to use @WebMvcTest.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.