Spring Boot #ApplicationProperties not using values from test profile - spring-boot

I have created a class annotated with #ApplicationProperties
#Configuration
#ConfigurationProperties(prefix = "myapp.security")
class SecurityProperties {
lateinit var signingKey: String
}
And a test to see if the values are retrieved from the config file
#ExtendWith(SpringExtension::class)
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
#SpringBootTest
#Profile("security-properties-test")
class SecurityPropertiesTest {
#Autowired
lateinit var securityProperties: SecurityProperties
#Test
fun `security properties are set`(){
securityProperties.signingKey shouldBe "theSigningKey"
}
}
When I create some values in the default application.yml, the value is picked up and everything works
spring:
jpa:
show-sql: true
myapp:
security:
signing-key: theSigningKey
But when I try to override the value in a profile, the value from the default profile is still used
spring:
jpa:
show-sql: true
myapp:
security:
signing-key: theSigningKey
---
spring:
profiles: security-properties-test
myapp:
security:
signing-key: anothertheSigningKey
What am I missing here?

You have used the wrong annotation on your test class. It should be annotated with #ActiveProfiles rather than #Profile.

Related

What's the properties file equivalent property for the #Profile(!dev) annotation?

In Spring-boot you can use the #Profile(!dev) annotation to exclude beans and classes from being provided when certain profiles are active or not active. Is there an equivalent property for this that can be used inside the application.yml?
You can use #ConditionalOnProperty.
#Bean
#ConditionalOnProperty(name = "stage", havingValue = "prod")
public NotificationSender notificationSender2() {
return new SmsNotification();
}
Which will be disabled if you have stage=dev in your application properties.
There's blog from Eugen on it: https://www.baeldung.com/spring-conditionalonproperty
Why not use profile seperators in configuration file?
---
spring:
profiles: dev
my-app.some-property: ...
---
spring:
profiles: uat
my-app.some-property: ...
Or like GeertPt said in, you can use org.springframework.boot.autoconfigure.condition.ConditionalOnProperty annotation to deal with your bean creation.
Even if you want you profile to be dev, you can use a feature flag to enable a bean. This might be helpful where you have to maintain multiple profiles.
For instance, I needed to log few properties on my stag server, but I was not willing to change in code base. So, with below, I only need to change the config-repo file and set the flag accordingly.
my-app-dev.yml
my-app:
cloud:
config:
log-details: true
log-ssl-properties: true
swagger:
enabled: false
ConditionalConfigurationPropertiesLogger.java
#Slf4j
#Component
#Profile({"native", "dev"})
#ConditionalOnProperty(name = "my-app.cloud.config.log-details", havingValue = "true")
public class ConditionalConfigurationPropertiesLogger implements CommandLineRunner {
#Override
public void run(String... args) {
log.info(" <details> ");
}
}
}

Springboot 2.0 JUnit test #Tranactional rollback doesn't works

I migrated some projects from Springboot 1.5.10 to 2.0.
Springboot 2.0.3Release, JDK10, mysql, hikari-cp
After this work, in JUnit test, all data in test cases remains at database. I think it doesn't works #Tranactional - org.springframework.transaction.annotation.Transactional
Here is part of application.yml and test class.
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
jpa:
show-sql: true
hibernate:
ddl-auto: none
database: mysql
database-platform: org.hibernate.dialect.MySQL5Dialect
Here is datasource.
#Configuration
#EnableTransactionManagement
public class DatasourceJPAConfig {
#Bean
#Primary
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
}
Here is part of JUnit test class.
#Transactional
#Rollback(true)
#RunWith(SpringRunner.class)
#ActiveProfiles("local")
#SpringBootTest
public class RepoTests {
#Autowired
private TestRepository testRepository;
#Test
public void saveTest() {
var name = "test";
var description = "test description"
var item = TestDomain.builder()
.name(name)
.description(description)
.build();
testRepository.save(item);
var optional = testRepository.findById(item.getId());
assertTrue(optional.isPresent());
assertEquals(optional.get().getDescription(), description);
assertEquals(optional.get().getName(), name);
}
}
after to run saveTest method, increase 1 row at database.
Add datasource to test and set auto commit to false
#Autowired
private DataSource dataSource;
And inside test
((HikariDataSource)dataSource).setAutoCommit(false);

Spring Test Dont have access on TestEntityManager

I'm trying execute some test with #DataJpaTest but I cant save my object to create my assertions.
Doc for TestEntityManager
When I try save my entity, I have the following result on log:
15/02/2018 14:58:40.565 WARN [main] org.hibernate.engine.jdbc.spi.SqlExceptionHelper: SQL Error: -5501, SQLState: 42501
15/02/2018 14:58:40.565 ERROR [main] org.hibernate.engine.jdbc.spi.SqlExceptionHelper: user lacks privilege or object not found: MY_VIEW in statement [select validviewl0_.cpf as cpf1_0_0_, validacaol0_.rating as rating7_0_0_ from dbo.my_view validviewl0_ where validviewl0_.cpf=?]
This is my annotations on test class:
#ActiveProfiles("test")
#RunWith(SpringRunner.class)
#DataJpaTest
#AutoConfigureTestDatabase(replace = Replace.ANY, connection = EmbeddedDatabaseConnection.HSQL)
public class MyRepositoryTest {
#Autowired
private TestEntityManager testEntityManager
#Autowired
private MyRepository myRepository;
#Before
public void setup() {
Assert.assertTrue(testEntityManager.getEntityManager().isOpen());
testEntityManager.persist(MyEntity.builder()
.cpf("11122233344").build());
testEntityManager.flush();
}
#After
public void after() {
testEntityManager.clear();
}
}
The BIG problem is that I dont know how to granw this access and it is about this message: user lacks privilege or object not found: MY_VIEW
Obs.: The real database (not in-memory and not on this test) is MS SQL Server.
It's not because of user permissions but tables are not created in your in-memory database so you need to add generate-ddl to your properties.
Also try annotating test with:
#RunWith(SpringRunner.class)
#AutoConfigureTestDatabase(replace = Replace.ANY)
#Transactional
#SpringBootTest
Add H2 or HSQL database for testing (or equivalent for Maven):
testCompile 'com.h2database:h2'
Application.yml properties example:
spring:
jpa:
database: default
generate-ddl: true
properties:
hibernate:
show_sql: true
use_sql_comments: true
format_sql: true
datasource:
url: jdbc:h2:mem:your_test_db;DB_CLOSE_ON_EXIT=FALSE
username: sa
password:
driverClassName: org.h2.Driver
If you mark your test with #Transactional, database will be roll backed after test so you wouldn't need to use #After to clear it. More info at Should my tests be #Transactional?
If this does not work, try simple EntityManager instead of TestEntityManager.

Loading initial test data in H2 in spring boot

I am using Spring Boot 1.5.8.Release and writing test cases using H2 in memory database. Currently in each test case class, we have #Before annotation, where we insert data using Spring Data classes.
I want to know, can I have a single place in project where we can define data for our all test cases. The database tables are created by Hybernate using entity classes. The only desired thing is about inserting data from single place instead of from #Before in each test case class.
I tried to use data.sql containing Insert statements but with it, Spring does not generate schema objects (tables) due to which I get table not found errors. I do not want to specify Create Table statement for each table in schema.sql
application-test.yml
spring:
datasource:
url: jdbc:h2:mem:test;
driverClassName: org.h2.Driver
username: sa
password:
jpa:
database: h2
database-platform: org.hibernate.dialect.H2Dialect
hibernate:
ddl-auto: create
naming.physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
properties:
hibernate:
show_sql: true
format_sql: false
Schema.sql
CREATE SCHEMA AB AUTHORIZATION SA;
AbcControllerTest.java
#RunWith(SpringRunner.class)
#ContextConfiguration(initializers = ConfigFileApplicationContextInitializer.class)
#SpringBootTest(classes = WebApp.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#AutoConfigureMockMvc
#ActiveProfiles("test")
public class AbcControllerTest {
#Autowired
private MockMvc mockMvc;
#Autowired
private LeDataService leDataService;
#Before
public void setup() {
MyInfo myInfo = new MyInfo();
..............
..............
leDataService.save(myInfo);
}
#Test
public void getAbcTest() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/api/v1/Abcs/1234567/12345678")
.with(SecurityMockMvcRequestPostProcessors.user("test").password("test123"))
.with(SecurityMockMvcRequestPostProcessors.csrf()))
.andExpect(status().isOk())
}
}
create new class annotated with #Component #Profile({ "dev", "test" }) and that implements CommandLineRunner then inject dependencies
Override run() method with your initial data that came with CommandLineRunner
for example
#Component
#Profile({ "dev", "test" })
setupInitialData implements CommandLineRunner {
UserService userService;
//bla bla
#Override
#Transactional
public void run(String... args) {
User user = new User;
user.setName("test");
userService.save(user);
//bla bla
}
}

#DataJpaTest fails when using Eureka / Feign

I have the the following Spring Boot application (using Eureka and Feign):
#SpringBootApplication
#EnableFeignClients
#EnableRabbit
#EnableDiscoveryClient
#EnableTransactionManagement(proxyTargetClass = true)
public class EventServiceApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(EventServiceApplication.class, args);
}
}
and the following test, annotated with #SpringJpaTest:
#RunWith(SpringRunner.class)
#DataJpaTest(showSql = true)
public class EventRepositoryTest {
#Autowired
private TestEntityManager entityManager;
#Autowired
private EventRepository repository;
#Test
public void testPersist() {
this.entityManager.persist(new PhoneCall());
List<Event> list = this.repository.findAll();
assertEquals(1, list.size());
}
}
While running the test I receive the following error:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.netflix.discovery.EurekaClient] found for dependency [com.netflix.discovery.EurekaClient]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
Full stacktrace here
Is there a way to solve this issue? I've seen that it is caused by #EnableFeignClients and #EnableDiscoveryClient annotations.
Finally I managed to solve my issue in the following way:
Added bootstrap.yml with the following contents:
eureka:
client:
enabled: false
spring:
cloud:
discovery:
enabled: false
config:
enabled: false
I written a test configuration and referenced it in the test:
#ContextConfiguration(classes = EventServiceApplicationTest.class)
where EventServiceApplicationTest is:
#SpringBootApplication
#EnableTransactionManagement(proxyTargetClass = true)
public class EventServiceApplicationTest {}
I don't know if there is an easiest way but this works.
I had similar problem with #EnableDiscoveryClient.
I think that in such cases the easiest approach is put disabling information:
eureka:
client:
enabled: false
in src/test/resources/application.[properties|yml]. Then during tests running this configuration has higher priority than src/main/resources/application.[properties|yml].
Since I assume you're only intending to test your repository layer, you could filter out the unneeded beans from your ApplicationContext related to Feign, etc.
You can configure an exclude filter via the excludeFilters attribute of #DataJpaTest.
Details on filters can be found in the Spring Reference Manual.
Another option would be to disable auto-configuration for Feign, etc. -- in which case you might find this answer useful: Disable security for unit tests with spring boot
The easiest way is to add the following configuration in your test class:
#RunWith(SpringRunner.class)
#TestPropertySource(properties={"eureka.client.enabled=false"})
#DataJpaTest(showSql = true)
public class BankRepositoryTest {
}

Resources