Reputation: 2153
I have a SpringBoot app.
I have created this test:
@ContextConfiguration(classes={TestConfig.class})
@RunWith(SpringRunner.class)
@SpringBootTest
public class SuncionServiceITTest {
@Test
public void should_Find_2() {
// TODO
}
}
where
@Configuration
@EnableJpaRepositories(basePackages = "com.plats.bruts.repository")
@PropertySource("local-configuration.properties")
@EnableTransactionManagement
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
public class TestConfig {
}
and local configuration.properties
:
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=sa
but when I run the test. I got this error:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available
I also tried with:
@EnableJpaRepositories(basePackages = "com.plats.bruts.repository", entityManagerFactoryRef="emf")
but then I have the error:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'emf' available
Upvotes: 5
Views: 2981
Reputation: 2809
I prefer to use following approach (i don't like to create own bean configurator). As @svr correctly noticed (see previous answer) you don't add starter package for beans auto configure. I usually create different profiles: for local app running, for dev, prod and finally last one for tests. In my test profile (application-functests.yml) i configure all settings that needs for my functional tests (datasources, hibernate, cache and so on), i.e. my application-functests.yml of one of my projects:
spring:
http:
encoding:
charset: UTF-8
enabled: true
profiles: functests
jpa:
show-sql: true
properties:
hibernate:
format_sql: true
enable_lazy_load_no_trans: true
naming:
physical-strategy: com.goodt.drive.orgstructure.application.utils.SnakePhysicalNamingStrategy
hibernate:
ddl-auto: none
database-platform: org.hibernate.dialect.PostgreSQL9Dialect
datasource:
driver-class-name: org.postgresql.Driver
url: jdbc:postgresql://localhost:5432/monitor_service_functests
username: developer
password: 123
sql-script-encoding: UTF-8
liquibase:
change-log: classpath:db/changelog/changelog.xml
I have only specify profile for running test, therefore all of my functional tests are using functests profile, i.e.:
@SpringBootTest
@ActiveProfiles("functests")
public class TestEventRepository extends FunctionalTestBase {
@Test
public void testGetAll() {
Iterable<EventEntity> eventIterable = dbContext.getEventDataSource().findAll();
Iterator<EventEntity> it = eventIterable.iterator();
List<EventEntity> actualEvents = new ArrayList<>();
while (it.hasNext()) {
actualEvents.add(it.next());
}
List<EventCheckData> expectedEvents = new ArrayList<>() {{
add(new EventCheckData(1L, 1L, "body 1", 1L, 1L));
add(new EventCheckData(2L, 2L, "body 2", 2L, 2L));
add(new EventCheckData(3L, 3L, "body 3", 3L, 1L));
add(new EventCheckData(4L, 1L, "body 4", 2L, 1L));
add(new EventCheckData(5L, 2L, "body 5", 1L, 2L));
}};
EventSimpleChecker.check(expectedEvents, actualEvents);
}
}
In my code example i have base test class - FunctionalTestBase which is used for interact with liquibase (toggle it to apply migrations)
Upvotes: 2
Reputation: 75994
Looks like you are missing below starter dependency. This starter dependency has all the necessary dependencies needed to configure the jpa
repositories.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
Upvotes: 4
Reputation:
This is an approach of how to configure several data sources in one application. I have tested it for spring-webmvc
and graphql-java
, but I think it can be useful for spring-boot
as well.
spring-data-jpa
For each database we should enable JPA repositories and specify the base packages for the corresponding interfaces. Also for each database we should specify the entity manager factory and the base packages for corresponding entities, as well as the transaction manager and the data source, of course.
To do this, we'll include in our application one configuration class for data JPA and three inner classes for each database. See the Simple GraphQL implementation.
DataJpaConfig.java
package org.drakonoved.graphql;
@Configuration
@PropertySource(value = "classpath:resources/application.properties", encoding = "UTF-8")
public class DataJpaConfig {
private final String basePackage = "org.drakonoved.graphql";
@EnableJpaRepositories(
basePackages = basePackage + ".repository.usersdb",
entityManagerFactoryRef = "usersdbEntityManagerFactory",
transactionManagerRef = "usersdbTransactionManager")
public class UsersDBJpaConfig {
@Bean("usersdbEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean usersDBEntityManagerFactoryBean(
@Value("${datasource.usersdb.script}") String script) {
return createEntityManagerFactoryBean(
script, "usersdb", basePackage + ".dto.usersdb");
}
@Bean("usersdbTransactionManager")
public PlatformTransactionManager usersDBTransactionManager(
@Qualifier("usersdbEntityManagerFactory")
LocalContainerEntityManagerFactoryBean factoryBean) {
return new JpaTransactionManager(factoryBean.getNativeEntityManagerFactory());
}
}
@EnableJpaRepositories(
basePackages = basePackage + ".repository.rolesdb",
entityManagerFactoryRef = "rolesdbEntityManagerFactory",
transactionManagerRef = "rolesdbTransactionManager")
public class RolesDBJpaConfig {
@Bean("rolesdbEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean rolesDBEntityManagerFactoryBean(
@Value("${datasource.rolesdb.script}") String script) {
return createEntityManagerFactoryBean(
script, "rolesdb", basePackage + ".dto.rolesdb");
}
@Bean("rolesdbTransactionManager")
public PlatformTransactionManager rolesDBTransactionManager(
@Qualifier("rolesdbEntityManagerFactory")
LocalContainerEntityManagerFactoryBean factoryBean) {
return new JpaTransactionManager(factoryBean.getNativeEntityManagerFactory());
}
}
@EnableJpaRepositories(
basePackages = basePackage + ".repository.usersnrolesdb",
entityManagerFactoryRef = "usersnrolesdbEntityManagerFactory",
transactionManagerRef = "usersnrolesdbTransactionManager")
public class UsersNRolesDBJpaConfig {
@Bean("usersnrolesdbEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean usersNRolesDBEntityManagerFactoryBean(
@Value("${datasource.usersnrolesdb.script}") String script) {
return createEntityManagerFactoryBean(
script, "usersnrolesdb", basePackage + ".dto.usersnrolesdb");
}
@Bean("usersnrolesdbTransactionManager")
public PlatformTransactionManager usersNRolesDBTransactionManager(
@Qualifier("usersnrolesdbEntityManagerFactory")
LocalContainerEntityManagerFactoryBean factoryBean) {
return new JpaTransactionManager(factoryBean.getNativeEntityManagerFactory());
}
}
//////// //////// //////// //////// //////// //////// //////// ////////
private LocalContainerEntityManagerFactoryBean createEntityManagerFactoryBean(
String script, String dbname, String packagesToScan) {
var factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.setName(dbname)
.addScript(script)
.build());
factoryBean.setPersistenceUnitName(dbname + "EntityManagerFactory");
factoryBean.setPackagesToScan(packagesToScan);
factoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
var properties = new HashMap<String, Object>();
properties.put("hibernate.hbm2ddl.auto", "none");
properties.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
factoryBean.setJpaPropertyMap(properties);
return factoryBean;
}
}
Upvotes: 2