@WebMvcTest 测试类中的 UnsatisfiedDependencyException
Posted
技术标签:
【中文标题】@WebMvcTest 测试类中的 UnsatisfiedDependencyException【英文标题】:UnsatisfiedDependencyException in a @WebMvcTest test class 【发布时间】:2018-10-04 16:47:50 【问题描述】:将@Service 添加到控制器后,我的单元测试失败。 该项目是 Spring-boot v 2.0.1.RELEASE。我花了很多时间试图找到答案,但没有运气。在我添加 @Service 注释并且我的服务类中有一个存储库之前,该测试有效。
堆栈跟踪:
2018-04-24 12:57:12.487 警告 940 --- [主要] o.s.w.c.s.GenericWebApplicationContext:遇到异常 在上下文初始化期间 - 取消刷新尝试: org.springframework.beans.factory.UnsatisfiedDependencyException: 创建名为“fleetController”的 bean 时出错:不满意 通过字段“服务”表达的依赖关系;嵌套异常是 org.springframework.beans.factory.NoSuchBeanDefinitionException: 否 'uk.co.vw.lead.service.ContactUsService' 类型的合格 bean 可用:预计至少有 1 个符合 autowire 条件的 bean 候选人。依赖注解: @org.springframework.beans.factory.annotation.Autowired(required=true)
控制器:
@Slf4j
@RestController
@RequestMapping(value = VERSION, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public class FleetController
public static final String VERSION = "1.0";
@Autowired
private ContactUsService service;
@InitBinder
public void initBinder(final WebDataBinder webDataBinder)
webDataBinder.registerCustomEditor(NatureOfEnquiryEnum.class, new NatureOfEnquiryEnumConverter());
webDataBinder.registerCustomEditor(FleetSizeEnum.class, new FleetSizeEnumConverter());
@PostMapping(value = "/fleet/contact-us")
public ResponseEntity contactUs(@Valid ContactUsDTO formDTO)
service.createForm(formDTO);
return new ResponseEntity(HttpStatus.NO_CONTENT);
@PostMapping(value = "/fleet/request-demo")
public ResponseEntity requestDemo(@Valid RequestDemoDTO demoDTO)
return new ResponseEntity(HttpStatus.NO_CONTENT);
服务:
@Service
public class ContactUsServiceImpl implements ContactUsService
@Autowired
private FleetRepository repository;
@Override
public void createForm(ContactUsDTO formDTO)
ContactUsForm form = populateContactUsForm(formDTO);
repository.save(form);
测试类:
@RunWith(JUnitPlatform.class)
@WebMvcTest(FleetController.class)
@ExtendWith(SpringExtension.class)
public class FleetControllerTest
private final String CONTACT_US_URL = "/fleet/contact-us";
@Autowired
private MockMvc mockMvc;
@MockBean
private FleetRepository repository;
@Autowired
private ContactUsService service;
@Test
public void contactUsSuccessTest() throws Exception
this.mockMvc.perform( post("/" + VERSION + CONTACT_US_URL)
.contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE)
.param("firstname", "John")
.param("lastname", "Doe")
.param("company", "Skynet")
.param("emailAddress", "john.connor@sky.net")
.param("telephone", "020 8759 4294")
.param("natureOfEnquiry", "new")
.param("comments", "some comments")
.param("recaptchaResponse", "success"))
.andExpect(status().isNoContent());
@Test
public void contactUsMissingRequiredFieldsTest() throws Exception
this.mockMvc.perform( post("/1.0/fleet/contact-us")
.contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE))
.andExpect(status().isBadRequest());
请帮忙,因为我不知道发生了什么。
【问题讨论】:
【参考方案1】:使用 @WebMvcTest
注释的测试类是仅关注 Spring MVC 组件的测试:控制器。
因此,您的单元测试中声明的服务字段无法自动装配:
@Autowired
private ContactUsService service;
所以你也应该模拟这个依赖:
@MockBean
private ContactUsService service;
还要注意,由于FleetController
没有任何直接依赖于FleetRepository
,因此不需要模拟此 bean:
@MockBean
private FleetRepository repository;
更糟糕的是,它会在上下文中添加一个模拟,这可能会在您的测试期间产生副作用。您必须只模拟被测控制器的直接依赖关系。
如果您只想模拟一些 bean 而不是所有不是控制器的 bean,请不要使用 @WebMvcTest
而不是使用将加载整个上下文的 @SpringBootTest
。
然后在测试类中声明你想用@MockBean
模拟的类。
【讨论】:
谢谢,现在有意义了! 为什么我们不能在@WebMvcTest
下使用来自Mockito 的@Mock
?我得到了同样的NoSuchBeanDefinitionException
。
@Eric Huang 因为@Mock
是一个模拟注释。为了让它可用,您需要一个 mockito junit5 扩展,但实际上您不希望这样:您希望保留 @ExtendWith(SpringExtension.class)
以加载 spring 上下文,同时可以模拟 bean。您可以参考其他问题:***.com/questions/44200720/…
@davidxxx 感谢您的回复。并且非常感谢链接..以上是关于@WebMvcTest 测试类中的 UnsatisfiedDependencyException的主要内容,如果未能解决你的问题,请参考以下文章
如何在@WebMvcTest 测试中忽略@EnableWebSecurity 注释类
SpringBoot @WebMvcTest,自动装配 RestTemplateBuilder
使用 @WebMvcTest 测试中的 ApplicationContext 异常