You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot @RestController测试报错:依赖注入失败及ApplicationContext加载异常

Spring Boot @RestController测试报错:No qualifying bean of type 'MemberService' available

问题描述

在Spring Boot中编写@RestController的测试代码时,出现以下错误:

java.lang.IllegalStateException: Failed to load ApplicationContext
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:132)

---------------------------------------------------------------------------

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'memberController' defined in file [C:\dev\react\Kculter\target\classes\com\prac\react\controller\MemberController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.prac.react.service.MemberService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

--------------------------------------------------------------------------------------------------
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.prac.react.service.MemberService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

已为MemberService添加@Service注解、MemberController添加@RestController注解,但问题依旧。相关代码如下:

MemberControllerTest.java

package com.prac.react.controller;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.prac.react.model.dto.Member;
import com.prac.react.service.MemberServiceTest;



@WebMvcTest(MemberController.class)
public class MemberControllerTest {

    @Autowired
    MockMvc mvc; // 用于测试虚拟HTTP请求的实例
    @Autowired
    ObjectMapper obm; 

    Logger logger = LoggerFactory.getLogger(MemberServiceTest.class);

    @Test
    @DisplayName("登录测试 1 ") // 模拟会员已存在场景的测试代码
    void testSignInMember() throws Exception {
        // given
        Member mb = new Member(1, "hankgood95@gmail.com", "이욱재", true);

        String requestBody = obm.writeValueAsString(mb);
        mvc.perform(post("/member")
                .content(requestBody)
                .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk()) // 状态码为200
                .andExpect(content().string(".com")) // 返回内容包含.com
                .andDo(print()); // 打印请求相关信息
    }
}

MemberController.java

package com.prac.react.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.prac.react.model.dto.Member;
import com.prac.react.service.MemberService;

/* 该文件是处理会员注册、登录、会员信息修改等会员相关操作的控制器 */

@RestController
public class MemberController {

    // 用于打印日志的实例
    Logger logger = LoggerFactory.getLogger(MemberController.class);
    // 用于依赖注入的MemberService实例
    MemberService ms;

    public MemberController(MemberService ms){
        this.ms = ms; // 依赖注入
    }

    @PostMapping("member")
    public Member SignInMember(@RequestBody Member member){
        
        if(ms.checkMember(member.getEmail()) > 0){ // 会员已存在时进入
            // 会员已存在,需携带当前Member信息跳转至主页
            member.setCheckMember(true);
            return member;
        }else{// 首次注册时进入
            // 非会员,需跳转至注册页面
            member.setCheckMember(false);
            return member;
        }
    }
}

MemberService.java

package com.prac.react.service;

import org.springframework.stereotype.Service;

import com.prac.react.model.dao.MemberDao;

@Service
public class MemberService {
    
    MemberDao md;

    // 通过构造函数注入MemberDao实例,注意:当存在多个依赖注入时必须添加@Autowired注解
    public MemberService(MemberDao md){
        this.md = md;
    }

    public int checkMember(String email){
        return md.checkMember(email);
    }
}

问题根源

@WebMvcTest注解的设计目标是仅加载Web层相关Bean(如@RestController、@Controller、@ControllerAdvice等),不会自动加载Service、Repository层的Bean。因此测试上下文启动时,Spring找不到MemberService的实例,导致控制器的依赖注入失败。

解决方案

方案一:使用@MockBean模拟MemberService(推荐单元测试使用)

因为控制器单元测试只需要验证请求处理逻辑,不需要真实的Service实现,用@MockBean创建一个模拟的MemberService实例注入到控制器即可:

修改后的MemberControllerTest.java:

package com.prac.react.controller;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.mockito.Mockito.when;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.prac.react.model.dto.Member;
import com.prac.react.service.MemberService;

@WebMvcTest(MemberController.class)
public class MemberControllerTest {

    @Autowired
    MockMvc mvc; 
    @Autowired
    ObjectMapper obm; 

    @MockBean // 模拟MemberService实例,注入到控制器
    MemberService memberService;

    Logger logger = LoggerFactory.getLogger(MemberControllerTest.class); // 修正Logger引用为当前测试类

    @Test
    @DisplayName("登录测试 1 - 模拟会员已存在场景")
    void testSignInMember() throws Exception {
        // given
        Member mb = new Member(1, "hankgood95@gmail.com", "이욱재", true);
        // 模拟Service的checkMember方法返回1(表示会员存在)
        when(memberService.checkMember(mb.getEmail())).thenReturn(1);

        String requestBody = obm.writeValueAsString(mb);
        mvc.perform(post("/member")
                .content(requestBody)
                .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().string("true")) // 断言返回的Member中checkMember为true
                .andDo(print());
    }
}

说明:

  • @MockBean会让Spring自动创建MemberService的模拟实例,解决依赖缺失问题
  • 用when(...).thenReturn(...)指定模拟方法的返回值,模拟业务场景
  • 修正了原代码中Logger的错误引用(原代码用了MemberServiceTest,改为当前测试类)
  • 调整了断言内容,原断言.com不符合实际返回结果,改为断言checkMember为true

方案二:改用@SpringBootTest + @AutoConfigureMockMvc(集成测试使用)

如果需要使用真实的Service、Dao层实现,测试完整的业务流程,可以用@SpringBootTest加载整个应用上下文,配合@AutoConfigureMockMvc启用MockMvc:

修改测试类的注解:

@SpringBootTest
@AutoConfigureMockMvc
public class MemberControllerTest {
    // 其余代码可保持不变,或根据真实业务场景调整
}

说明:

  • @SpringBootTest会加载整个Spring应用上下文,所有Bean(包括Service、Dao)都会被初始化
  • 这种方式启动速度较慢,适合集成测试,而非单元测试

额外优化:简化构造函数注入

Spring 4.3+支持无@Autowired的构造函数注入,但为了代码可读性,建议使用Lombok的@RequiredArgsConstructor注解自动生成构造函数,简化代码:

修改MemberController.java:

@RestController
@RequiredArgsConstructor // Lombok注解,自动生成含final字段的构造函数
public class MemberController {
    private final Logger logger = LoggerFactory.getLogger(MemberController.class);
    private final MemberService ms; // 必须声明为final

    @PostMapping("member")
    public Member SignInMember(@RequestBody Member member){
        // 业务逻辑不变
    }
}

修改MemberService.java:

@Service
@RequiredArgsConstructor
public class MemberService {
    private final MemberDao md;

    public int checkMember(String email){
        return md.checkMember(email);
    }
}

内容的提问来源于stack exchange,提问作者codingRookie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 05:27:18