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

Spring Boot集成测试无法Autowired注入Component标注Bean的问题

问题

编写Spring Boot集成测试实现数据库记录创建与读取功能时,运行测试出现如下错误:

Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 3.914 s <<< FAILURE! -- in com.juno.databasedemo.dao.AuthorDaoImplIntegrationTest
com.juno.databasedemo.dao.AuthorDaoImplIntegrationTest.testThatAuthorCanBeCreatedAndRecalled -- Time elapsed: 0.057 s <<< ERROR!
org.junit.jupiter.api.extension.ParameterResolutionException: Failed to resolve parameter [com.juno.dao.impl.AuthorDaoImpl underTest] in constructor [public com.juno.databasedemo.dao.AuthorDaoImplIntegrationTest(com.juno.dao.impl.AuthorDaoImpl)]: No qualifying bean of type 'com.juno.dao.impl.AuthorDaoImpl' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
    at java.base/java.util.Optional.orElseGet(Optional.java:364)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.juno.dao.impl.AuthorDaoImpl' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1880)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1406)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1353)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.resolveDependency(AbstractAutowireCapableBeanFactory.java:471)
    at org.springframework.beans.factory.annotation.ParameterResolutionDelegate.resolveDependency(ParameterResolutionDelegate.java:136)
    at org.springframework.test.context.junit.jupiter.SpringExtension.resolveParameter(SpringExtension.java:342)
    ... 3 more

相关代码如下:

AuthorDaoImplIntegrationTest.java

package com.juno.databasedemo.dao;

import static org.assertj.core.api.Assertions.*;

import java.util.Optional;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import com.juno.dao.impl.AuthorDaoImpl;
import com.juno.databasedemo.TestDataUtil;
import com.juno.domain.Author;

@SpringBootTest
@ExtendWith(SpringExtension.class)
class AuthorDaoImplIntegrationTest {
    
    private AuthorDaoImpl underTest;

    @Autowired
    public AuthorDaoImplIntegrationTest(AuthorDaoImpl underTest) {
        this.underTest = underTest;
    }

    @Test
    void testThatAuthorCanBeCreatedAndRecalled() {
        Author author = TestDataUtil.createAuthorForTesting();

        // Test Author Creation
        underTest.create(author);

        // Test Author Recall
        Optional<Author> result = underTest.findOne(author.getId());

        // Assertion
        assertThat(result).isPresent();
        assertThat(result.get()).isEqualTo(author);
    }
}

AuthorDaoImpl.java

package com.juno.dao.impl;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Optional;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Component;

import com.juno.dao.AuthorDao;
import com.juno.domain.Author;

@Component
public class AuthorDaoImpl implements AuthorDao {
    
    private final JdbcTemplate jdbcTemplate;

    public AuthorDaoImpl(final JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @Override
    public void create(Author author) {
        this.jdbcTemplate.update("INSERT INTO author(id, name, age) values (?, ?, ?)",
        author.getId(), author.getName(), author.getAge());
    }

    @Override
    public Optional<Author> findOne(int id) {
        List<Author> results = jdbcTemplate.query(
            "SELECT id, name, age FROM author where id = ? LIMIT = 1", 
            new AuthorRowMapper(), id);

        return results.stream().findFirst();
    }

    public static class AuthorRowMapper implements RowMapper<Author> {

        @Override
        public Author mapRow(ResultSet rs, int rowNum) throws SQLException {
            Author author = Author.builder()
                                .id(rs.getInt("id"))
                                .name(rs.getString("name"))
                                .age(rs.getInt("age"))
                                .build();
            
            return author;
        }
        
    }
}

DatabaseConfig.java

package com.juno.config;

import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;

@Configuration
public class DatabaseConfig {
    
    @Bean
    public JdbcTemplate jdbcTemplate(final DataSource dataSource) {
        JdbcTemplate restTemplate = new JdbcTemplate(dataSource);

        return restTemplate;
    }
    
}

尝试在DatabaseConfig中为DataSource和AuthorDaoImpl创建Bean,但问题依旧。

解决方案

1. 修复Spring组件扫描范围问题

错误核心是Spring容器找不到AuthorDaoImpl的Bean,原因是组件扫描范围不包含com.juno.dao.impl包:

  • Spring Boot默认扫描启动类所在包及其子包。如果启动类在com.juno.databasedemo下,com.juno.dao不在默认扫描范围内,导致@Component注解的AuthorDaoImpl无法被Spring识别。

解决方法(选其一即可):

  • 将启动类移到com.juno包下,所有子包都会被自动扫描。
  • 在启动类上添加@ComponentScan(basePackages = "com.juno"),显式指定全局扫描范围。
  • 在测试类的@SpringBootTest注解中指定需要加载的Bean:@SpringBootTest(classes = {DatabaseConfig.class, AuthorDaoImpl.class})。

2. 修正SQL语法错误

AuthorDaoImpl的findOne方法中SQL存在语法错误:LIMIT = 1应改为LIMIT 1,否则后续测试会出现SQL执行失败问题。修正后的代码:

@Override
public Optional<Author> findOne(int id) {
    List<Author> results = jdbcTemplate.query(
        "SELECT id, name, age FROM author where id = ? LIMIT 1", 
        new AuthorRowMapper(), id);

    return results.stream().findFirst();
}

3. (可选)简化测试类注入方式

测试类的构造器注入逻辑没问题,也可以直接使用字段注入简化代码:

@SpringBootTest
@ExtendWith(SpringExtension.class)
class AuthorDaoImplIntegrationTest {
    
    @Autowired
    private AuthorDaoImpl underTest;

    // 测试方法保持不变...
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 03:35:01