Spring boot multiple database cause NoSuchBeanDefinitionException by integration testing - spring-boot

By configuring application to use two datasource instances, it cause an issue in one of my integration tests with the following message - "Unsatisfied dependency expressed through method 'entityManagerFactoryBean' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}"
Here is the bean that stores the information for both database instances:
#Component
public class DataSourceRouting extends AbstractRoutingDataSource {
private final DataSourcePrimeConfig dataSourcePrimeConfig;
private final DataSourceSecondConfig dataSourceSecondConfig;
private final DataSourceContextHolder dataSourceContextHolder;
public DataSourceRouting(DataSourceContextHolder dataSourceContextHolder, DataSourcePrimeConfig dataSourcePrimeConfig,
DataSourceSecondConfig dataSourceSecondConfig) {
this.dataSourcePrimeConfig = dataSourcePrimeConfig;
this.dataSourceSecondConfig = dataSourceSecondConfig;
this.dataSourceContextHolder = dataSourceContextHolder;
Map<Object, Object> dataSourceMap = new HashMap<>();
dataSourceMap.put(DataSourceEnum.DATASOURCE_PRIME, dataSourceOneDataSource());
dataSourceMap.put(DataSourceEnum.DATASOURCE_SECOND, dataSourceTwoDataSource());
this.setTargetDataSources(dataSourceMap);
this.setDefaultTargetDataSource(dataSourceOneDataSource());
}
#Override
protected Object determineCurrentLookupKey() {
return this.dataSourceContextHolder.getBranchContext();
}
public DataSource dataSourceOneDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(dataSourcePrimeConfig.getUrl());
dataSource.setUsername(dataSourcePrimeConfig.getUsername());
dataSource.setPassword(dataSourcePrimeConfig.getPassword());
return dataSource;
}
public DataSource dataSourceTwoDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(dataSourceSecondConfig.getUrl());
dataSource.setUsername(dataSourceSecondConfig.getUsername());
dataSource.setPassword(dataSourceSecondConfig.getPassword());
return dataSource;
}
}
Here is the configuration class:
#Configuration
#EnableJpaRepositories(basePackages = "test.project.repository", transactionManagerRef = "transcationManager", entityManagerFactoryRef = "entityManager")
#EnableTransactionManagement
#RequiredArgsConstructor
#DependsOn("dataSourceRouting")
public class DataSourceConfig {
private final DataSourceRouting dataSourceRouting;
#Bean
#Primary
public DataSource dataSource() {
return dataSourceRouting;
}
#Bean(name = "entityManager")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(EntityManagerFactoryBuilder builder) {
return builder.dataSource(dataSource()).packages("test.project").build();
}
#Bean(name = "transcationManager")
public JpaTransactionManager transactionManager(
#Autowired #Qualifier("entityManager") LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) {
return new JpaTransactionManager(entityManagerFactoryBean.getObject());
}
}
And here is the failing test:
#SpringBootTest
#Import(value = DataSourceConfig.class)
#RunWith(SpringRunner.class)
#ActiveProfiles("test")
public class MailBodyProviderServiceTest {
#Autowired
private MailService mailService;
#Autowired
private ReportService reportService;
#MockBean
private JPATransactionDataRepository jpaTransactionDataRepository;
#Autowired
private MailBodyBuilder builder;
#Autowired
private DataSourceRouting dataSourceRouting;
#Autowired
private DataSource dataSource;
#Autowired
private LocalContainerEntityManagerFactoryBean entityManagerFactoryBean;
#Autowired
private JpaTransactionManager jpaTransactionManager;
#Autowired
private EntityManagerFactoryBuilder entityManagerFactoryBuilder;
#Rule
public SmtpServerRule smtpServerRule = new SmtpServerRule(2525);
#Test
public void shouldSendSingleMail() throws MessagingException {
when(this.jpaTransactionDataRepository.mapTransactionData()).thenReturn(generateReportData());
mailService.sendEmail(new ReportEvent(this, "report event", EventType.CREDIT_CARD));
MimeMessage[] receivedMessages = smtpServerRule.getMessages();
assertEquals(3, receivedMessages.length);
MimeMessage current = receivedMessages[0];
String contentType = current.getContentType();
assertTrue(contentType.contains("multipart"));
}
private static Map<Date, List<TransactionDto>> generateReportData(){
Date today = new Date();
List<Object[]> objects = new ArrayList<>();
Object[] object1 = new Object[] { today, AuthStatus.AUTH_CONFIRMED.name(), ProcessingType.DIRECT.name(), BigDecimal.valueOf(10l)};
Object[] object2 = new Object[] { today, AuthStatus.AUTH_REJECTED.name(), ProcessingType.DIRECT.name(), BigDecimal.valueOf(10l)};
Object[] object3 = new Object[] { new Date(today.getTime() + (1000 * 60 * 60 * 24)), AuthStatus.AUTH_CANCELED.name(), ProcessingType.TAN.name(), BigDecimal.valueOf(10l)};
Object[] object4 = new Object[] { new Date(today.getTime() + (1000 * 60 * 60 * 24)), AuthStatus.AUTH_FAILED.name(), ProcessingType.TAN.name(), BigDecimal.valueOf(10l)};
objects.add(object1);
objects.add(object2);
objects.add(object3);
objects.add(object4);
return TransactionMapper.mapFromDatabaseQuery(objects);
}
}
I try with #TestConfiguration, also to exclude DataSourceConfig, but nothing helps. Hope someone to have idea what I do wrong or miss :)

Related

unable run Quartz JDBCJobStore with AbstractRoutingDataSource

I have implemented the application using Spring RoutingDataSource.
Spring -> DS1,
DS2
Based on the logged in URL I am changing the Data Source. it is working fine.
Coming to the quartz, I am unable to change the data source dynamically. Always jobs are getting scheduled on default data source.
#Configuration
public class SchedulerConfig {
#Autowired
private DataSource dataSource;
#Autowired
private QuartzProperties quartzProperties;
#Bean
public JobFactory jobFactory(ApplicationContext applicationContext) {
AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
jobFactory.setApplicationContext(applicationContext);
return jobFactory;
}
#Bean
public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory) {
Properties properties = new Properties();
properties.putAll(quartzProperties.getProperties());
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setJobFactory(jobFactory);
factory.setDataSource(dataSource);
factory.setGlobalJobListeners(jobListener());
factory.setQuartzProperties(properties);
return factory;
}
#Bean
public JobListenerSupport jobListener() {
return new JobListener();
}
}
Data Source Routing Configuration::
#Component
public class DataSourceRouting extends AbstractRoutingDataSource {
private DataSourceOneConfig dataSourceOneConfig;
private DataSourceTwoConfig dataSourceTwoConfig;
private DataSourceContextHolder dataSourceContextHolder;
public DataSourceRouting(DataSourceContextHolder dataSourceContextHolder, DataSourceOneConfig dataSourceOneConfig,
DataSourceTwoConfig dataSourceTwoConfig) {
this.dataSourceOneConfig = dataSourceOneConfig;
this.dataSourceTwoConfig = dataSourceTwoConfig;
this.dataSourceContextHolder = dataSourceContextHolder;
Map<Object, Object> dataSourceMap = new HashMap<>();
dataSourceMap.put(DataSourceEnum.tenant1, dataSourceOneDataSource());
dataSourceMap.put(DataSourceEnum.tenant2, dataSourceTwoDataSource());
this.setTargetDataSources(dataSourceMap);
this.setDefaultTargetDataSource(dataSourceTwoDataSource());
}
#Override
protected Object determineCurrentLookupKey() {
return dataSourceContextHolder.getBranchContext();
}
public DataSource dataSourceOneDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(dataSourceOneConfig.getUrl());
dataSource.setUsername(dataSourceOneConfig.getUsername());
dataSource.setPassword(dataSourceOneConfig.getPassword());
return dataSource;
}
public DataSource dataSourceTwoDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(dataSourceTwoConfig.getUrl());
dataSource.setUsername(dataSourceTwoConfig.getUsername());
dataSource.setPassword(dataSourceTwoConfig.getPassword());
return dataSource;
}
}
Data Soruce Config ::
#RequiredArgsConstructor
#DependsOn("dataSourceRouting")
public class DataSourceConfig {
private final DataSourceRouting dataSourceRouting;
#Bean
#Primary
public DataSource dataSource() {
return dataSourceRouting;
}
#Bean(name = "entityManager")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(EntityManagerFactoryBuilder builder) {
return builder.dataSource(dataSource()).packages("com.model.entity").build();
}
#Bean(name = "transcationManager")
public JpaTransactionManager transactionManager(
#Autowired #Qualifier("entityManager") LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) {
return new JpaTransactionManager(entityManagerFactoryBean.getObject());
}
}

org.springframework.orm.jpa.JpaSystemException: could not initialize proxy [Order#orderdate] - no Session;

My spring boot v2.5.5 application has master slave mysql db configured.
Primary Data Source Config
#EnableJpaRepositories(
basePackages = "com.dummy",
excludeFilters = #ComponentScan.Filter(ReadOnlyRepository.class),
entityManagerFactoryRef = "primaryEntityManagerFactory",
transactionManagerRef = "primaryTransactionManager"
)
#Configuration
public class PrimaryDataSourceConfig {
#Autowired
private Environment env;
#Value("${master.jdbc.url}")
private String jdbcURL;
#Bean
#Primary
public DataSource primaryDataSource() throws Exception {
return DataSourceBuilder.create()
.driverClassName("com.mysql.jdbc.Driver")
.url(jdbcURL)
.username("root")
.password("root").build();
}
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory() throws Exception {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(primaryDataSource());
em.setPackagesToScan("com.dummy");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(false);
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
#Bean
#Primary
public PlatformTransactionManager primaryTransactionManager() throws Exception {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(primaryEntityManagerFactory().getObject());
return transactionManager;
}
final Properties additionalProperties() {
final Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("primary.hibernate.hbm2ddl.auto"));
hibernateProperties.setProperty("hibernate.dialect", env.getProperty("primary.hibernate.dialect"));
hibernateProperties.setProperty("hibernate.show_sql", env.getProperty( "primary.hibernate.show_sql"));
hibernateProperties.setProperty("hibernate.cache.use_second_level_cache", "false");
return hibernateProperties;
}
}
Slave Datasource Config
#Configuration
#EnableJpaRepositories(
basePackages = "com.dummy.submodule",
includeFilters = #ComponentScan.Filter(ReadOnlyRepository.class),
entityManagerFactoryRef = "readOnlyEntityManagerFactory",
transactionManagerRef = "readOnlyTransactionManager"
)
public class ReadOnlyDataSourceConfig {
#Autowired
private Environment env;
#Value("${slave.jdbc.url}")
private String jdbcURL;
#Bean
public DataSource readOnlyDataSource() throws Exception {
return DataSourceBuilder.create()
.driverClassName("com.mysql.jdbc.Driver")
.url(jdbcURL)
.username("root")
.password("root").build();
}
#Bean
public LocalContainerEntityManagerFactoryBean readOnlyEntityManagerFactory() throws Exception {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(readOnlyDataSource());
em.setPackagesToScan("com.dummy.submodule");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(false);
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
#Bean
public PlatformTransactionManager readOnlyTransactionManager() throws Exception {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(readOnlyEntityManagerFactory().getObject());
return transactionManager;
}
final Properties additionalProperties() {
final Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("readonly.hibernate.hbm2ddl.auto"));
hibernateProperties.setProperty("hibernate.dialect", env.getProperty("readonly.hibernate.dialect"));
hibernateProperties.setProperty("hibernate.show_sql", env.getProperty( "readonly.hibernate.show_sql"));
hibernateProperties.setProperty("hibernate.cache.use_second_level_cache", "false");
return hibernateProperties;
}
}
Entity
#Entity
#Getter
#Setter
public class Product implements Serializable {
private static final long serialVersionUID = 8135071385764991866L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToOne(fetch = FetchType.LAZY)
#NotNull
#JoinColumn(name = "status")
private Order order
}
#Getter
#Setter
#Entity
public class Order implements Serializable {
private static final long serialVersionUID = 8135071385764991879L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private Date orderdate;
}
I am trying to fetch Product from read only(slave) db in my service layer
#Service
#AllArgsConstructor
public class ProductService{
private ProductRepository repo;
public void performOperation(){
Optional<Product> product = repo.findById(1l, Product.class);
if(product.isPresent()){
Order order = product.get().getOrder();
Date orderDate = order.getOrderDate(); // this line gives below exception
}
}
}
Readonly Repository:
#Repository
#ReadOnlyRepository
public interface ProductRepository extends JpaRepository<Product, Long> {
<T> Optional<T> findById(final Long id, Class<T> type);
}
Exception:
2021-10-22 12:35:11,109 ERROR [http-nio-8080-exec-8] com.dummy.logging.LoggingClass:41 Exception_Occurred::{}
org.springframework.orm.jpa.JpaSystemException: could not initialize proxy [com.dummy.submodule.entities.Order#orderdate] - no Session; nested exception is org.hibernate.LazyInitializationException: could not initialize proxy [com.dummy.submodule.entities.Order#orderdate] - no Session
Note: The LazyInitializationException occurs only when I am fetching Product from slave db. When same operation i am trying to perform using master db I am not getting LazyInitializationException.
This issue for now i have handled by making Order as FetchType.EAGER.
But i am trying to find out reason behind this in case of master slave db and how to achieve it with LAZY fetch type.
Annotate performOperation with #Transactional like below:
#Service
#AllArgsConstructor
public class ProductService{
private ProductRepository repo;
#Transactional
public void performOperation(){
Optional<Product> product = repo.findById(1l, Product.class);
if(product.isPresent()){
Order order = product.get().getOrder();
Date orderDate = order.getOrderDate(); // this line gives below exception
}
}
}

Spring boot configuration for #Transactional for both JPA and spring-JDBC-templete

in my project, I am using both JPA and spring-jdbc-template & NamedParameterTemplate.
I need to get transaction support for both.
So how to configure #Transactional for both JPA & spring-JDBC ?
Here are the 2 classes I used for configuring those.
Class number 1: PersistenceConfiguration
This is the class that declares transaction-management should be enabled.
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = {"com.google.product.repository"},
excludeFilters = #ComponentScan.Filter(type = FilterType.REGEX, pattern = "com.google.product.repository.mongoRepository.*.*Repository"))
public class PersistenceConfiguration {
#Autowired
private DataSource dataSource;
#Autowired
private Properties entityManagerProperties;
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource);
em.setPackagesToScan("com.google.product.model");
final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(entityManagerProperties);
return em;
}
}
Class number 2: ProdDatabaseConfiguration
This is the class that declares beans releted toJDBC & JPA. for example primaryJdbcTemplate ,secondaryJdbcTemplate & entityManagerProperties.
#Configuration
#PropertySource({"classpath:database-prod.properties"})
#Profile("prod")
public class ProdDatabaseConfiguration {
private static final Logger LOG = LoggerFactory.getLogger(ProdDatabaseConfiguration.class);
#Value("${jdbc.jndiName}")
private String jndiName;
#Value("${hibernate.dialect}")
private String hibernateDialect;
#Value("${hibernate.show_sql}")
private String hibernateShowSql;
#Value("${hibernate.cache.use_second_level_cache}")
private String hibernateSecondLevelCache;
#Value("${hibernate.cache.use_query_cache}")
private String hibernateQueryCache;
#Value("${jadira.usertype.databaseZone}")
private String databaseZone;
#Value("${jadira.usertype.javaZone}")
private String javaZone;
#Value("${mongo.jndiName}")
private String mongoJndiName;
#Bean
public DataSource dataSource() {
JndiDataSourceLookup jndiDataSourceLookup = new JndiDataSourceLookup();
return jndiDataSourceLookup.getDataSource(jndiName);
}
#Bean(name = "entityManagerProperties")
public Properties additionalProperties() {
final Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", "none");
hibernateProperties.setProperty("hibernate.dialect", hibernateDialect);
hibernateProperties.setProperty("hibernate.show_sql", hibernateShowSql);
hibernateProperties.setProperty("hibernate.cache.use_second_level_cache", hibernateSecondLevelCache);
hibernateProperties.setProperty("hibernate.cache.use_query_cache", hibernateQueryCache);
hibernateProperties.setProperty("jadira.usertype.databaseZone", databaseZone);
hibernateProperties.setProperty("jadira.usertype.javaZone", javaZone);
return hibernateProperties;
}
#Bean(name = "primaryJdbcTemplate")
public JdbcTemplate primaryJdbcTemplate() {
JndiDataSourceLookup jndiDataSourceLookup = new JndiDataSourceLookup();
return new JdbcTemplate(jndiDataSourceLookup.getDataSource(jndiName));
}
#Bean(name = "secondaryJdbcTemplate")
public NamedParameterJdbcTemplate secondaryJdbcTemplate() {
JndiDataSourceLookup jndiDataSourceLookup = new JndiDataSourceLookup();
return new NamedParameterJdbcTemplate(jndiDataSourceLookup.getDataSource(jndiName));
}
Because you are only using one datasource you can remove all the configuration and just use the spring.datasource properties.
Transaction will also work out of the box because you will have only this datasource.
Read more about this topic in the official documentation:
https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-sql

Spring #Transactional rollback not working

#RestController
#RequestMapping("/Api/Order")
public class OrderController {
private OrderService service;
private RefundService refundService;
#AsCustomer
#DeleteMapping(value = "/{orderID}/RefundApplication")
#Transactional(rollbackFor = RuntimeException.class)
public Map cancelRefundApplication(#SessionAttribute("user") User user,
#PathVariable("orderID") String orderID) {
Order order = service.getOrderByID(orderID);
RefundApplication application = refundService.get(orderID);
order.setState(Order.STATE_PAYED);
refundService.delete(orderID);
service.updateOrder(order);
throw new EntityNotFoundException("test");
}
...
I want transaction created in cancelRefundApplication method to be rolled back when a RuntimeException is thrown, and to be commit if no RuntimeException is thrown. But I find the transaction is not rolled back even if a RuntimeException is thrown. For test perpose, I change the code to make it always throw a EntityNotFoundException, and test it with following test method. After running the test, I check database and find refund application data is deleted, which means transaction is not rolled back and #Transactional annotation is not working.
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = {WebConfig.class, RootConfig.class, DataConfig.class})
#WebAppConfiguration
class OrderControllerTest {
#Autowired
OrderController controller;
#Autowired
UserService userService;
#Autowired
OrderService orderService;
#Autowired
AppWideExceptionHandler exceptionHandler;
private User customer;
private User seller;
private HashMap<String, Object> sessionAttrs;
private ResultMatcher success = jsonPath("$.code")
.value("0");
private MockMvc mockMvc;
#Test
void cancelRefundApplication() throws Exception {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
String path = String.format("/Api/Order/%s%d0001/RefundApplication"
, simpleDateFormat.format(new Date()), customer.getID());
mockMvc.perform(delete(path)
.characterEncoding("UTF-8")
.sessionAttrs(sessionAttrs))
.andDo(print())
.andExpect(success);
}
...
This is DataConfig class:
#Configuration
#MapperScan("youshu.mapper")
public class DataConfig {
#Bean
public DataSource dataSource() {
// org.apache.ibatis.logging.LogFactory.useLog4J2Logging();
PooledDataSource pds = new PooledDataSource();
pds.setDriver("com.mysql.cj.jdbc.Driver");
pds.setUsername(...);
pds.setPassword(...);
pds.setUrl("jdbc:mysql://XXXX");
return pds;
}
#Bean
public JdbcOperations jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
#Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setTypeAliasesPackage("youshu.entity");
return sessionFactory.getObject();
}
#Bean
public DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
#Bean
public SqlSessionTemplate sqlSession(SqlSessionFactory factory){
return new SqlSessionTemplate(factory);
}
}
Transactions need to be enabled manually by annotating config class with #EnableTransactionManagement
Check include or not TransactionalTestExecutionListener in your test, if not add: #TestExecutionListeners(listeners = {TransactionalTestExecutionListener.class})

Junit test cases for JPA repositories

I am new to junit, I have a repository as follows:
#Repository
public interface ChartRepository extends JpaRepository<Chart, Integer>{
}
and My Chart Entity class is follows:
#Entity
#Table(name = "Chart")
public class Chart {
#Column(name = "ENT_ID")
private String entID;
#Column(name = "ent_NAME")
private String entName;
#Column(name = "ent_PRODUCER_ID")
private String entProducerId;
#Id
#Column(name = "ent_Rc_ID")
#SequenceGenerator(name = "ent_RC_ID_SEQ", sequenceName="ent_RC_ID_SEQ", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ent_RC_ID_SEQ")
private Integer entReceiveId;
#Column(name = "JOB_ID")
private Integer jobId;
#Column(name = "CREATE_DT")
private Timestamp createdDate;
//getters and Setters
}
Now, Can we able to write test cases for the repository class. If so how can we do that.Can anyone please suggest me with some code samples.
You can create a #DataJpaTest and #Autowire your repository into it. For example:
#RunWith(SpringRunner.class)
#DataJpaTest
public class MyJpaTest {
#Autowired
private ChartRepository chartRepository;
#Test
public void myTest() {
...
}
}
See this for more: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-testing-autoconfigured-jpa-test
I would strongly recomment to use any in-memory DB to test you JPA repository and dont use mock test framework like Mockito, EasyMock, etc. As in Dao layer, there should not be any business logic to mock. it should be simple read/write operation.
I use h2database for this.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(
classes = {DatabaseConfig.class},
loader = AnnotationConfigContextLoader.class)
public class ChartRepositoryTest {
#Autowired
private ChartRepository cartRepository;
#Test
public void testfind() {
// do find , insert and validate the response
}
}
testCompile('com.h2database:h2:1.4.196')
This is wha database config file looks like
#Configuration
#EnableJpaRepositories(basePackages = "com.mypackage.repository")
#PropertySource("application-test.properties")
#EnableTransactionManagement
public class DatabaseConfig {
#Autowired
private Environment env;
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
dataSource.setUrl(env.getProperty("jdbc.url"));
dataSource.setUsername(env.getProperty("jdbc.user"));
dataSource.setPassword(env.getProperty("jdbc.pass"));
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan(new String[] { "com.mypackage.v2" });
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "create");
properties.setProperty("hibernate.dialect","org.hibernate.dialect.H2Dialect");
return properties;
}
}

Resources