首页 > 解决方案 > 通过字段表达的不满足依赖——Springboot的Application,组件和测试类都在同一个包中

问题描述

我的理解是 SpringBootApplication 注解包含 ComponentScan

https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-using-springbootapplication-annotation.html

在Application.main()中发现并打印了bean,为什么单元测试找不到呢?

此单元测试失败:

org.springframework.beans.factory.UnsatisfiedDependencyException:创建名为“com.pds.pdssr.etlfile.EtlFileServicesTest”的bean时出错:通过字段“etlFileServices”表示不满足的依赖关系;嵌套异常是 org.springframework.beans.factory.NoSuchBeanDefinitionException:没有“com.pds.pdssr.etlfile.EtlFileServices”类型的合格 bean 可用:预计至少有 1 个有资格作为自动装配候选者的 bean。依赖注解:{@org.springframework.beans.factory.annotation.Autowired(required=true)}

使用适当的调试级别,即“org.springframework.context.annotation”="debug" 我可以看到在组件扫描期间发现了 bean。

然而,单元测试的结果是:

[错误] getAll(com.pds.pdssr.etlfile.EtlFileServicesTest) 经过时间:0.007 s <<< 错误!org.springframework.beans.factory.UnsatisfiedDependencyException:创建名为“com.pds.pdssr.etlfile.EtlFileServicesTest”的bean时出错:通过字段“etlFileServices”表示不满足的依赖关系;嵌套异常是 org.springframework.beans.factory.NoSuchBeanDefinitionException:没有“com.pds.pdssr.etlfile.EtlFileServices”类型的合格 bean 可用:预计至少有 1 个有资格作为自动装配候选者的 bean。依赖注解:{@org.springframework.beans.factory.annotation.Autowired(required=true)} 原因:org.springframework.beans.factory.NoSuchBeanDefinitionException:没有'com.pds.pdssr.etlfile.EtlFileServices 类型的合格bean ' 可用的:预计至少有 1 个 bean 有资格作为 autowire 候选者。依赖注解:{@org.springframework.beans.factory.annotation.Autowired(required=true)}

应用程序:

package com.pds.pdssr.bootstrap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

//@EnableJpaRepositories("com.pds.pdsssr.jpa")
@SpringBootApplication
// @EntityScan("com.pds.pdssr.models")
public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {
        ApplicationContext applicationContext = SpringApplication.run(Application.class, args);
        for (String name : applicationContext.getBeanDefinitionNames()) {
            logger.info("bean: " + name);
        }
    }
}

组件:

包 com.pds.pdssr.bootstrap;

import java.util.List;

import javax.persistence.EntityManagerFactory;
import javax.transaction.Transactional;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import com.pds.pdssr.models.EtlFile;

@Repository
public class EtlFileServices {

    @Autowired
    private static EntityManagerFactory entityManagerFactory;

    public SessionFactory getSessionFactory() {
        SessionFactory sessionFactory = null;
        if (entityManagerFactory == null) {
            throw new IllegalStateException("entityManagerFactory is null");
        }
        sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
        if (sessionFactory == null) {
            throw new NullPointerException("factory is not a hibernate factory");
        }
        return sessionFactory;
    }


    @SuppressWarnings("unchecked")
    public List<EtlFile> getAll() {
        return getAll("etlFile",getSessionFactory().getCurrentSession());
    }

    @SuppressWarnings("rawtypes")
    protected List getAll(String tableName, Session session) {
        String queryText = "from " + tableName;
        return getList(tableName, queryText, session);
    }


    @SuppressWarnings("rawtypes")
    protected List getList(String tableName, String queryText, Session session) {
        long start = System.nanoTime();

        Query query = session.createQuery(queryText);
        List result = query.list();
        long end = System.nanoTime();
        long millis = (end - start) / 1000000;
        //logger.debug("table: " + tableName + " millis " + millis + " rows:  " + result.size());
        return result;
    }


}

测试类:

import java.util.List;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit4.SpringRunner;

import com.pds.pdssr.bootstrap.EtlFileServices;
import com.pds.pdssr.models.EtlFile;

@RunWith(SpringRunner.class)
public class EtlFileServicesTest {
    @Autowired
    private EtlFileServices etlFileServices;

    @Test 
    public void getAll() {
        List<EtlFile>  etlFiles = etlFileServices.getAll();
        assertNotNull(etlFiles);
    }

}

标签: spring-boot

解决方案


原答案:

你需要有

@RunWith(SpringRunner.class)
@SpringBootTest(classes = YourMainClass.class)

在您的测试课程中。

基于评论的进一步回答

如果你真的想SessionFactory在你的项目中拥有,你需要告诉spring框架明确地拥有SessionContext。可以通过添加来完成

spring.jpa.properties.hibernate.current_session_context_class = org.springframework.orm.hibernate5.SpringSessionContext

到你的配置文件。这是您的问题的一个工作示例

HTH


推荐阅读