I'm writing a test for a Spring boot Rest controller. This rest controller writes some values to the db.
I want to use in-memory database which Spring provides for this test. According to this doc I have to annotate the test class with #DataJpaTest, which causes this error:
java.lang.IllegalStateException: Failed to load ApplicationContext
Further down in the error stack trace I see the following exception was thrown:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource': Invocation of init method failed; nested exception is java.lang.IllegalStateException: Failed to replace DataSource with an embedded database for tests. If you want an embedded database please put a supported one on the classpath or tune the replace attribute of #AutoconfigureTestDatabase.
This is the test class which I'm working on:
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
#DataJpaTest
public class AuthenticationControllerFTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private AuthenticationManager authenticationManager;
#Autowired
private WebApplicationContext context;
#Autowired
private Filter springSecurityFilterChain;
#Before
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(context)
.addFilters(springSecurityFilterChain).build();
}
#Test
public void testCreate() throws Exception {
String exampleUserInfo = "{\"name\":\"Salam12333\",\"username\":\"test#test1.com\",\"password\":\"Salam12345\"}";
RequestBuilder requestBuilder = MockMvcRequestBuilders
.post("/signup")
.accept(MediaType.APPLICATION_JSON).content(exampleUserInfo)
.contentType(MediaType.APPLICATION_JSON);
MvcResult result = mockMvc.perform(requestBuilder).andReturn();
MockHttpServletResponse response = result.getResponse();
int status = response.getStatus();
Assert.assertEquals("http response status is wrong", 200, status);
}
}
What is causing this error ?
Edit 1
This is the content of my application.properties:
spring.datasource.username = hello
spring.datasource.password = hello
spring.datasource.driver-class-name= com.mysql.jdbc.Driver
spring.datasource.url = jdbc:mysql://localhost:3306/myproject?useSSL=false
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type=TRACE
logging.level.org.springframework.web=DEBUG
server.port = 8443
server.ssl.key-store = classpath:tomcat.keystore
server.ssl.key-store-password = hello
server.ssl.key-password = hello
server.ssl.enabled = true
server.ssl.key-alias=myproject
Edit 2
I added the following to my pom.xml:
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>test</scope>
</dependency>
I created application-test.properties with the following content:
spring.datasource.username= root
spring.datasource.password= password
spring.datasource.driver-class-name= org.h2.Driver
spring.datasource.url= jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
What is the username and passowrd ? Where should I set them ?
I also added #ActiveProfiles("test") to the test class, when I run the test I get an error which includes this line :
Caused by: org.hibernate.HibernateException: Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set
Assuming you annotate class with #SpringBootApplication, which enables auto-configuration and you have H2 dependency on classpath(see below) Spring Boot will see H2 in-memory database dependency and it will create javax.sql.DataSource implementation. Default connection URL is jdbc:h2:mem:testdb and the default username and password are: username: sa and password: empty.
application.properties file
spring.datasource.url=jdbc:h2:mem:tesdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.testWhileIdle = true
spring.datasource.validationQuery = SELECT 1
spring.jpa.show-sql = true
spring.h2.console.enabled=true // if you need console
H2 Dependency
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency> // If you need h2 web console
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
You can gain access to h2 console for management http://localhost:8080/h2-console
For Testing REST service with in-memory DB, you need to following things:
1. Add h2 dependency in pom.xml
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
2. Define h2 configuration in application.properties or application.yaml
spring.jpa.database = h2
spring.datasource.url=jdbc:hsqldb:mem:testdb
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.HSQLDialect
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create
3. Annotate you test class
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
Complete code will be like:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class AuthenticationControllerFTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private AuthenticationManager authenticationManager;
#Autowired
private WebApplicationContext context;
#Autowired
private Filter springSecurityFilterChain;
#Before
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(context)
.addFilters(springSecurityFilterChain).build();
}
#Test
public void testCreate() throws Exception {
String exampleUserInfo = "{\"name\":\"Salam12333\",\"username\":\"test#test1.com\",\"password\":\"Salam12345\"}";
RequestBuilder requestBuilder = MockMvcRequestBuilders
.post("/signup")
.accept(MediaType.APPLICATION_JSON).content(exampleUserInfo)
.contentType(MediaType.APPLICATION_JSON);
MvcResult result = mockMvc.perform(requestBuilder).andReturn();
MockHttpServletResponse response = result.getResponse();
int status = response.getStatus();
Assert.assertEquals("http response status is wrong", 200, status);
}
}
Remove both annotations #AutoConfigureMockMvc and #DataJpaTest. You are trying to test the complete applciation, so need the #SpringBootTest annotation. #DataJpaTest is only needed if you want to test only the data apllication slice. Have a look at this: https://spring.io/blog/2016/04/15/testing-improvements-in-spring-boot-1-4
In spring boot we do not require to add any thing additional for in memory database configuration except for jar file on class path and application property file (application.properties) on the class path (src/test/resources if maven is used) rest of the things will be taken care by spring boot (beauty of boot).
Another option is to provide profile specific properties file on the class path src/amin/resources (for example application-test.properties)
Both of the file are valid for test configurations
Sample configuration for property file is given below (consider HSQL DB jar on class path):
spring.jpa.hibernate.ddl-auto = create-drop
spring.jpa.database = HSQL
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.HSQLDialect
spring.datasource.driverClassName = org.hsqldb.jdbcDriver
spring.datasource.url: jdbc:hsqldb:mem:scratchdb
spring.datasource.username = sa
spring.datasource.password = pass
Maybe this helps.
spring.datasource.url=jdbc:hsqldb:mem:testdb
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.HSQLDialect
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create
See also Configure specific in memory database for testing purpose in Spring
I believe, you can use below in-memory db with integration test -
This will also help if you are using json[b](though it is in DB2 but some ops like inserting/updating not support with our code) datatype or any other field that is not present in DB2 (compatibility issue).
Then refer this TestContainer - Stackoverflow answer
Pom.xml
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<version>1.15.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>1.15.1</version>
<scope>test</scope>
</dependency>
XyzIT.java
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#ActiveProfiles("test")
#Testcontainers
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
#Test
void test(){
var mvcResult = mockMvc.perform(MockMvcRequestBuilders.post("/opportunities/process")
.header("emailId", "ravi.parekh#xyz.com")
.header("Authorization", "authorization")
.header("Content-Type", "application/json").content(objectMapper.writeValueAsString(opportunity))).andReturn();
}
Application-test.yml
datasource:
initialization-mode: always
schema: classpath*:schema-h2.sql #initial sql script to createDB
url: jdbc:tc:postgresql:11.9:///
jpa:
hibernate.ddl-auto: none
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
format_sql: true
default_schema: public
show-sql: true
Related
After updating to Spring Boot 2.6.8 with Java v11 and using Junit5 I'm not able to Mock anymore MongoTemplate
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes={RepositoryImpl.class})
class RepositoryImplTest {
#Autowired
private RepositoryImpl repositoryImpl;
#MockBean
private MongoTemplate db;
...
}
I get the following error
java.lang.IllegalStateException: Failed to load ApplicationContext Caused by: org.mockito.exceptions.base.MockitoException: Mockito cannot mock this class: class org.springframework.data.mongodb.core.MongoTemplate.
as per dependency I have in pom.xml
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
</dependency>
My spring boot test is throwing the below error during maven build.
"level":"ERROR","logger":"com.zaxxer.hikari.HikariConfig","msg":"HikariPool-1 - jdbcUrl is required with driverClassName."
Stacktrace:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'schedulerFactoryBean' defined in class path resource
[com/pit/SchedulerConfig.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: jdbcUrl is requir
ed with driverClassName.
Caused by: java.lang.IllegalArgumentException: jdbcUrl is required with driverClassName.
The method that throws an error in my MyApplicationTest.java
#SpringBootTest
#EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
#EnableConfigurationProperties(value = MyConfig.class)
class MyApplicationTest {
#Test
void contextLoads() {
assertNotNull(myController);
}
}
My pom has these dependencies in classpath.
spring-boot-starter-web
spring-boot-starter-test
spring-integration-sftp
postgresql
junit
quartz-scheduler
My Datasource bean is configured as below
#Configuration
public class MyDataSourceCfg {
private DataSource appDataSource() {
return DataSourceBuilder.create()
.driverClassName("org.postgresql.Driver")
.url(env.getProperty("url") // values are set from Environment
.username(env.getProperty("user"))
.password(env.getProperty("password")
.build();
}
}
Please tell me what is happening and how I avoid this error. I read about configuring Datasource in different way in case you have multiple database but I just have one postgres database. Please share your thoughts.
Considering that you have all relevant dependencies.
as Connect to PostgreSQL Database with Spring Data JPA such as :-
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
and in application.properties file:
spring.datasource.url=jdbc:postgresql://localhost:5432/dev
spring.datasource.username=dbuser
spring.datasource.password=dbpass
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL81Dialect
With SpringBoot's powerful autoconfiguration, you don't need to explicitly create a DataSource bean and if in case you want, use these properties values.
I'm trying to start my spring-boot-web app but I'm getting the following error :
2020-03-17 20:54:22.643 WARN 15640 --- [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.
2020-03-17 20:54:22.664 ERROR 15640 --- [ main] o.s.boot.SpringApplication : Application run failed
I configured the following ApplicationContext file :
#Configuration
#EnableJpaRepositories(basePackages = {"repos"})
public class AppConfig {
#Bean
public LocalEntityManagerFactoryBean entityManagerFactory() {
LocalEntityManagerFactoryBean factoryBean = new LocalEntityManagerFactoryBean();
factoryBean.setPersistenceUnitName("mydb");
return factoryBean;
}
#Bean
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
}
I need those beans because in one of my services I inject the following objects :
#Autowired
private EntityManagerFactory emf;
#PersistenceContext
private EntityManager em;
and my main app :
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
public static void main(String[]args)
{
//load the spring config class we configured
SpringApplication.run(AppConfig.class);
}
my dependencies in pom.xml :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.1.Final</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.11</version>
</dependency>
Solutions I tried but didnt work :
1)add extends SpringBootServletInitializer to both Application.java and Appconfig.java
2)Move the beans from the AppConfig.java to Application.java
3)Tried to set the following annotation on the application class :
#SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
4)Adding the following dependency to the pom.xml :
org.springframework.boot
spring-boot-starter-tomcat
2.2.5.RELEASE
I resolved my problem by adding dependancy 'spring-boot-starter-web'.
Make sure that your filename, class name and the name of the class inside the SpringApplication.run() function are the same.
Also, make sure you haven't forgotten the #SpringBootApplication annotation.
My solution :
In addition to the persistence.xml file I created application.properties file :
# Connection url for the database
spring.datasource.url=jdbc:postgresql://ip:port/db
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.hibernate.ddl-auto =update
spring.jpa.show-sql = true
chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQL9Dialect
spring.jpa.generate-ddl=true
server.port = 9091
Afterwards, in my Application.java I added the following annotations and extend :
#SpringBootApplication
#EnableJpaRepositories("repositories")
#EntityScan("dao")
public class Application extends SpringBootServletInitializer {
You can comment the <scope>provided</scope> in pom.xml file like below
You need to override configure method from SpringBootServletInitializer
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
I am trying to run a Spring Batch app that reads data from a SQL Server DB and writes to a csv file. Below is the DatabaseConfiguration file for the SQL Server DB:-
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
basePackages = {"com.sample.repository"},
entityManagerFactoryRef = "sampleEntityManagerFactory",
transactionManagerRef = "transManager"
)
public class CompensationConfiguration
{
#Primary
#Bean(name="cmpnDS")
#ConfigurationProperties(prefix = "sample.datasource.compensation")
public DataSource sampleDataSource() {
return DataSourceBuilder.create().build();
}
#Primary
#Bean(name = "sampleEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean sampleEntityManagerFactory(EntityManagerFactoryBuilder builder,
#Qualifier("cmpnDS") DataSource dataSource) {
return builder
.dataSource(dataSource)
.packages("com.opencodez.entity")
.build();
}
#Primary
#Bean(name = "transManager")
public PlatformTransactionManager hrprdTransactionManager(#Qualifier("sampleEntityManagerFactory")
EntityManagerFactory entityManagerFactoryBean) {
return new JpaTransactionManager(entityManagerFactoryBean);
}
}
Following is a snippet from the pom file:-
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>mybat</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>mybat</name>
<description>Demo project for Spring Boot</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<maven-jar-plugin.version>2.6</maven-jar-plugin.version>
<spring-cloud.version>Hoxton.RC2</spring-cloud.version>
</properties>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
and the following in the properties file:-
spring:
datasource:
url: jdbc:h2:mem:testdb
username: sa
password:
driver-class-name: org.h2.Driver
When I try to launch the app it is failing to start with the below error:-
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'h2Console' defined in class path resource [org/springframework/boot/autoconfigure/h2/H2ConsoleAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.web.servlet.ServletRegistrationBean]: Factory method 'h2Console' threw exception; nested exception is java.lang.IllegalArgumentException: dataSource or dataSourceClassName or jdbcUrl is required.
This app reads a SQL Server DB for processing records. The spring batch uses in memory DB H2Database. Is this a multi-datasource scenario? I didn't do any coding for the datasource configuration of H2 as it should be autoconfigured. I have all the required dependencies included in the pom - sprign-batch-core, devtools, h2 database, jpa etc.
I got around this by setting
spring.h2.console.enabled=false
in my spring boot application.properties file.
The doc for that property says that you could get rid of this by instead removing the pom dependency for spring-boot-devtools (detailed here).
You have to delete h2's related jar files in .m2 maven local repository, It's must be corrupted.
After that, you have to run "mvn spring-boot:run" again, Maybe more that one jar was corrupted so check it and reapet recipe (every time you need to run that command after delete that jar).
I created two Datasource Configuration classes, one for each database, and marked the h2 datasource as primary. The app started fine after this change.
I am learning Spring Boot and in my first set up I got this problem:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured
I looked up solutions on the web and did find some, including those from Stackoverflow, but none of them works.
My simple code:
#SpringBootApplication
#RestController
public class SpringBootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootDemoApplication.class, args);
}
#RequestMapping(value = "/")
public String response(){
return "You made it!";
}
}
My POM:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
My application.properties:
spring.datasource.url=jdbc:mysql://localhost:3306/hrdb?autoReconnect=true
spring.datasource.username=root
spring.datasource.password=passw0rd
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
I also created a file as the following:
#Configuration
public class DBConfig {
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/hr?autoReconnect=true");
dataSource.setUsername("root");
dataSource.setPassword("passw0rd");
return dataSource;
}
}
I got the mentioned error either in Unit Test or starting the service. The only way I find out to make it work is to disable data source auto config:
#SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
Need your help. Thanks.
Check your DB config - it seems to overwrite Spring's default data source, but the url is different than in application.properties: "jdbc:mysql://localhost:3306/hr?autoReconnect=true"
In the properties you have:
"jdbc:mysql://localhost:3306/hrdb?autoReconnect=true"
"hr" vs "hrdb".
I would get rid of this class altogether and instead declare the relevant JDBC driver in your pom.xml and let Spring take care of the connection.