I am trying to write some tests for my application and encountered following problem:
I defined a application-test.yml with folling content:
server:
port: 8085
spring:
security:
oauth2:
resourceserver:
jwt:
# change localhost:8081 with container name
issuer-uri: http://localhost:8081/auth/realms/drivingschool
jwk-set-uri: http://localhost:8081/auth/realms/drivingschool/protocol/openid-connect/certs
keycloak:
realm: drivingschool
auth-server-url: http://localhost:8081/auth
ssl-required: external
resource: client-interface
use-resource-role-mappings: true
credentials:
secret: xxx
bearer-only: true
My test class:
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
#ActiveProfiles("test")
public class StudentControllerTests {
#Autowired
private MockMvc mockMvc;
#Autowired
private StudentService service;
#MockBean
private StudentRepository repository;
#Test
public void contextLoads(){}
//more tests
}
the test all pass green BUT in the log i can see, that my app tries to connect to a database configured in my (basic) application.yml.
ava.sql.SQLNonTransientConnectionException: Could not connect to address=(host=localhost)(port=9005)(type=master) : Socket fail to connect to host:localhost, port:9005. Verbindungsaufbau abgelehnt (Connection refused)
at org.mariadb.jdbc.internal.util.exceptions.ExceptionFactory.createException(ExceptionFactory.java:73) ~[mariadb-java-client-2.6.1.jar:na]
at org.mariadb.jdbc.internal.util.exceptions.ExceptionFactory.create(ExceptionFactory.java:192) ~[mariadb-java-client-2.6.1.jar:na]
jpa:
database-platform: org.hibernate.dialect.MariaDBDialect
hibernate:
use-new-id-generator-mappings: false
ddl-auto: create
datasource:
url: jdbc:mariadb://localhost:9005/waterloo
username: waterloo
password: xxx
driver-class-name: org.mariadb.jdbc.Driver
when creating a application-prod.yml and moving all content from application.yml to application-prod.yml it tells me I have to configure a datasource URL
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: Factory method 'dataSource' threw exception; nested exception is org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Failed to determine a suitable driver class
I have the following questions:
Do the application.yml files get layered (*-test.yml settings on top of application.yml)?
Why does Spring try to build a connection to my database when I am not setting a datasource on my application-test.yml AND mocking the repository on the test?
Is it normal that Spring trys to establish a connection at this part?
3.1) If not: How to i prevent it from doing so?
Thanks and kind regards!
Failed to determine a suitable driver class
You need to add mariadb driver dependency to your gradle or maven file.
https://mvnrepository.com/artifact/org.mariadb.jdbc/mariadb-java-client/2.6.2
Make sure that dependency scope is suitable for test
If you already have and its still not working try to clean and rebuild your project.
Your Questions:
Do the application.yml files get layered (*-test.yml settings on top
of application.yml)?
If you add #ActiveProfiles("test") to you TestClass Spring will try to find an application-test.yml and overrrides application.yml properties with the given properties
Why does Spring try to build a connection to my database when I am not
setting a datasource on my application-test.yml AND mocking the
repository on the test?
Thats the magic of spring boot - it has default configurations for everything. You just need to set the Datasource properties and it will create the bean by itself.
Is it normal that Spring trys to establish a connection at this part? 3.1) If not: How to i prevent it from doing so?
You are starting the whole spring context with #SpringBootTest Annotation.
So it will startup all Repositories and try to establish connection to your database. If you don't want spring to startup the database layer you can just use #WebMvcTest
eg:
#RunWith(SpringRunner.class)
#WebMvcTest
#ActiveProfiles("test")
public class StudentControllerTests {
#Autowired
private MockMvc mockMvc;
#Test
public void contextLoads(){}
//more tests
}
Check this out: https://spring.io/guides/gs/testing-web/
If you need to startup the whole SpringContext you can also disable Spring Data AutoConfiguration with:
#SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class
})
Check this out: https://www.baeldung.com/spring-data-disable-auto-config
missed following annotation:
#EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class})
Related
I'm very new to junit testing. How to write junit test real database call from mybatis.xml file.
Please find the below code.
#RunWith(SpringRunner.class)
//#MybatisTest
#SpringBootTest
public class HotelMapperTest {
#Autowired
private HotelMapper hotelMapper;
#Test
public void selectByCityIdTest() {
Hotel hotel = hotelMapper.selectByCityId(1);
assertThat(hotel.getName()).isEqualTo("Conrad Treasury Place");
assertThat(hotel.getAddress()).isEqualTo("William & George Streets");
assertThat(hotel.getZip()).isEqualTo("4001");
}
when i run the junit testing i'm getting below exception:
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found):
Herer my question is how we'll test the real database, When enable the #MybatisTest it's looking for datasource, already we specified all properties in applicaiton.properties. In this time i'm getting below exception:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource':
You can config mybatis mapper location in spring configuration file (such as application.yml).
mybatis configuration:
mybatis:
mapper-locations:
- classpath*:mapper/*.xml
I have a requirement to fetch DB username and password from Vault. So I have removed the default implementation (spring.datasource.url,spring.datasource.username,spring.datasource.password)
and added the following code in DAOImpl class.
Code
#Autowired
private JdbcTemplate jdbcTemplate;
#Bean
#Primary
public DataSource dataSource()
{
return DataSourceBuilder.create().username("someusername").password("somepassword")
.url("someurl")
.driverClassName("oracle.jdbc.driver.OracleDriver").build();
}
It was working perfectly. But when I added a new DAOImpl class I got the following Exception. Is it necessay to add the above code snippet in all the DAOImpl
classes. Is there a way to configure dataSource in single class and use it in all the DAOImpl classes
Exception
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'dataSource': Requested bean is currently in creation: Is there an unresolvable circular reference?
I have an application that uses spring boot 2 and logs metrics from micrometer. I want to log jdbc (mysql) min, max, and active connections periodically. I also want to use #RefreshScope on my datasource bean to prevent hikari binding exceptions when injecting configs on the fly from spring admin. I find that when I use #RefreshScope on config class/datasource bean JDBC does not register itself with the MeterRegistry.
Is it possible to have JDBC register itself with the MeterRegistry with #RefreshScope?
Is there a way to progammatically register JDBC with the MeterRegistry in my bean definition?
#Configuration
#EnableAutoConfiguration
#EnableTransactionManagement
#RefreshScope
public class DbConfig {
#Primary
#Bean(name = "dataSource")
#RefreshScope
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
Removing #RefreshScope allows JDBC to automatically register with the MeterRegistry but causes the below exception on config change:
org.springframework.boot.context.properties.ConfigurationPropertiesBindException: Error creating bean with name 'dataSource': Could not bind properties to 'HikariDataSource' : prefix=spring.datasource, ignoreInvalidFields=false, ignoreUnknownFields=true; nested exception is org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'spring.datasource' to javax.sql.DataSource
Add javax.sql.DataSource as an extra refreshable. application.yml file example:
spring:
cloud:
refresh.extra-refreshable:
- javax.sql.DataSource
and remove #RefreshScope from your class.
Other solution would be cast the DataSource to HikariDataSource.
I use the first solution because of DataSource creation is done by external library in my application.
Reference: https://github.com/spring-cloud/spring-cloud-commons/issues/318
Using spring boot yaml config, I have a datasource that looks like this:
datasource:
url: jdbc:postgresql://somehost/somedb
username: username
password: password
hikari:
connection-timeout: 250
maximum-pool-size: 1
minimum-idle: 0
I can succesfully point to different DBs based on profile, but I'd like to setup a profile that does not use this datasource at all. When I use that profile, however, I get this:
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to auto-configure a DataSource: 'spring.datasource.url' is not specified and no embedded datasource could be auto-configured.
Reason: Failed to determine a suitable driver class
How do I use this datasource in some profiles, but not in others?
You can skip the bean for specific profiles using `#Profile("!dev") annotation
profile names can also be prefixed with a NOT operator e.g. “!dev” to exclude them from a profile
from docs here
If a given profile is prefixed with the NOT operator (!), the annotated component will be registered if the profile is not active — for example, given #Profile({"p1", "!p2"}), registration will occur if profile 'p1' is active or if profile 'p2' is not active.
Profiles can also be configured in XML – the tag has “profiles” attribute which takes comma separated values of the applicable profiles:here
<beans profile="dev">
<bean id="devDatasourceConfig"
class="org.baeldung.profiles.DevDatasourceConfig" />
</beans>
Change to:
spring:
datasource:
url: jdbc:postgresql://somehost/somedb
username: username
password: password
hikari:
connection-timeout: 250
maximum-pool-size: 1
minimum-idle: 0
Springboot works with Autoconfiguration by default, but you can customize excluding some AutoConfiguration classes
Edit your configuration to skip AutoConfiguration:
#EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
Make your own datasource by profile
#Bean
#Profile("dev")
DataSource dataSourceDevProfile(org.springframework.core.env.Environment environment) throws Exception {
return DataSourceBuilder.create().url("").driverClassName("").password("").username("").build();
}
#Bean
#Profile("!dev")
DataSource dataSourceNoDev(org.springframework.core.env.Environment environment) throws Exception {
return DataSourceBuilder.create().url(environment.getProperty("spring.datasource.url")).driverClassName("").password(environment.getProperty("spring.datasource.password")).username(environment.getProperty("spring.datasource.username")).build();
}
Or Totally Programatically
#Bean
DataSource dataSource2(org.springframework.core.env.Environment environment) throws Exception {
if (environment.acceptsProfiles("dev")){
//return datasource dev
}else{
//return datasource prod
}
Using gradle (3.4.1) with an integrationTest configuration, the tests using the ConfigurationProperties of Spring Boot (1.5.1.RELEASE) is failing to initialize even though the application initializes correctly (./gradlew bootRun). The class annotated with ConfigurationProperties is similar to the following
#Component
#ConfigurationProperties(prefix = "foo")
#Validated
public class AppConfiguration {
#NonNull
private URL serviceUrl;
...
The configuration file does have getters and setters. The error that is generated is similar to the following
java.lang.IllegalStateException: Failed to load ApplicationContext
....
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'AppConfiguration': Could not bind properties to AppConfiguration
....
Caused by: org.springframework.validation.BindException: org.springframework.boot.bind.RelaxedDataBinder$RelaxedBeanPropertyBindingResult
Field error in object 'foo' on field 'serviceUrl': rejected value [null]; codes ...
The configuration class of the integration test is annotated as follows
#Configuration
#ComponentScan(...)
#EnableConfigurationProperties
#EnableIntegration
public static class ContextConfiguration {}
The test class had the following annotations
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class ReleaseTest {
...
After looking at the Spring Boot code for the ConfigurationPropertiesBindingPostProcessor#postProcessBeforeInitialization() it suggested that the property source was not being discovered. Adding the org.springframework.boot:spring-boot-starter-test artifact as a compile-time dependency and modifying the context configuration of the test class to
#ContextConfiguration(initializers = ConfigFileApplicationContextInitializer.class)
the AppConfiguration class was initialized properly using a YAML-based properties file.
An alternative is to add
#TestPropertySource("classpath:/application.properties")
This approach doesn't require the spring-boot-starter-test dependency and requires that a "traditional" properties file is used (a YAML file will not work with this approach).