Как поднять тестовую БД в Spring (при тестировании)

Пишу тесты для своего приложения. Использую тестовую БД.

Столкнулся с проблемой:

Error creating bean with name 'jpaDepartmentDaoImpl': Injection of persistence dependencies failed;
nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException:   
No qualifying bean of type 'javax.persistence.EntityManagerFactory' available: 
expected single matching bean but found 2: testLocalContainerEntityManagerFactoryBean,localContainerEntityManagerFactoryBean

Я понимаю, что Spring ругается на то, что не может понять какой бин подставить, но как мне ему указать, что при тестах использовать мою тестовую конфигурацию, а при обычном использовании - обычную?

Место возникновения ошибки: введите сюда описание изображения

введите сюда описание изображения

DispatcherServletInitTest

package com.aimprosoft.hopak.util.config.dispatcher;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.HiddenHttpMethodFilter;
import org.springframework.web.servlet.DispatcherServlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration;

@TestOnly
@Configuration
@ComponentScan("com.aimprosoft.hopak")
public class DispatcherServletInitTest implements WebApplicationInitializer {

    @Override
    public void onStartup(@NotNull ServletContext servletContext) {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.scan("com.aimprosoft.hopak");
        ctx.setServletContext(servletContext);
        servletContext.addListener(new ContextLoaderListener(ctx));
        ServletRegistration.Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
        servlet.addMapping("/");
        servlet.setLoadOnStartup(1);
        
        registerHiddenFieldFilter(servletContext);
    }
    private void registerHiddenFieldFilter(ServletContext aContext) {
        aContext.addFilter("hiddenHttpMethodFilter",
                new HiddenHttpMethodFilter()).addMappingForUrlPatterns(null ,true, "/*");
    }
}

JpaConfigTest package com.aimprosoft.hopak.util.config;

import org.jetbrains.annotations.TestOnly;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.test.context.TestPropertySource;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.persistence.EntityManagerFactory;
import java.util.Properties;

@TestOnly
@Configuration
@TestPropertySource("classpath:testDataBase.properties")
@EnableTransactionManagement
@ComponentScan("com.aimprosoft.hopak")
public class JpaConfigTest {

    @Value("${spring.datasource.url}")
    private String url;
    @Value("${spring.datasource.password}")
    private String password;
    @Value("${spring.datasource.username}")
    private String username;
    @Value("${spring.datasource.driver-class-name}")
    private String driverClassName;
    @Value("${spring.datasource.database-platform}")
    private String databasePlatform;

    private final Properties prop = new Properties();

    {
        prop.setProperty("hibernate.show_sql", "true");
        prop.setProperty("hibernate.format_sql", "true");
    }

    @Bean
    public DriverManagerDataSource testDriverManagerDataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean testLocalContainerEntityManagerFactoryBean() {
        LocalContainerEntityManagerFactoryBean localContainer = new LocalContainerEntityManagerFactoryBean();
        localContainer.setDataSource(testDriverManagerDataSource());
        localContainer.setPackagesToScan("com.aimprosoft.hopak");
        localContainer.setJpaVendorAdapter(testHibernateJpaVendorAdapter());
        localContainer.setJpaProperties(prop);
        return localContainer;
    }

    @Bean
    public HibernateJpaVendorAdapter testHibernateJpaVendorAdapter() {
        HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
        hibernateJpaVendorAdapter.setDatabasePlatform(databasePlatform);
        return hibernateJpaVendorAdapter;
    }

    @Bean
    public PlatformTransactionManager testTransactionManager(@Qualifier("testLocalContainerEntityManagerFactoryBean") EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }
}

WebApplicationContextConfigTest

package com.aimprosoft.hopak.util.config;

import net.sf.oval.Validator;
import net.sf.oval.configuration.annotation.AnnotationsConfigurer;
import net.sf.oval.guard.GuardInterceptor;
import net.sf.oval.integration.spring.SpringCheckInitializationListener;
import net.sf.oval.integration.spring.SpringValidator;
import org.jetbrains.annotations.TestOnly;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@TestOnly
@Configuration
@EnableWebMvc
@ComponentScan("com.aimprosoft.hopak")
public class WebApplicationContextConfigTest implements WebMvcConfigurer {

    @Bean
    public InternalResourceViewResolver templateResolver() {
        InternalResourceViewResolver templateResolver = new InternalResourceViewResolver();
        templateResolver.setPrefix("/view");
        templateResolver.setSuffix(".jsp");
        return templateResolver;
    }

    @Bean
    public SpringValidator validator() {
        AnnotationsConfigurer springConfig = new AnnotationsConfigurer();
        springConfig.addCheckInitializationListener(SpringCheckInitializationListener.INSTANCE);
        Validator validator = new Validator(springConfig);
        return new SpringValidator(validator);
    }

    @Bean
    public GuardInterceptor guardInterceptor() {
        return new GuardInterceptor();
    }

}

Ответы (1 шт):

Автор решения: Илья Гопак

Я недооценил возможности спринга. И 90% он делает самостоятельно. Всё, что нам нужно, это создать ещё dataBase.properties (с одинаковыми названиями, как на скрине) и когда вы запустите тесты, спринг сам всё подтянет.

ВАЖНО: ПАПКИ ДОЛЖНЫ БЫТЬ ПОМЕЧЕНЫ,КАК RESOURCES/TEST RESOURCES!!!!!

Для этого в IntelliJIdea

  1. Ctrl + Alt + Shift + S введите сюда описание изображения

И так! Теперь, всё, что нам нужно:

введите сюда описание изображения

→ Ссылка