I'm in the process of setting up liquibase to manage my database in a new spring boot application. I need the liquibase dependency in my classpath to reset the database state after certain integration tests run. During my tests I do not want liquibase to be enabled via spring auto config during application context initialization. I've tried adding liquibase.enabled = false to the application.properties, however when I debug the LiquibaseAutoConfiguration class it appears that enabled is always set to true.
I'm not new to spring, but I am new to spring-boot's auto configuration. Has anyone had issues with spring boot not respecting properties in application.properties?
My setup is fairly minimal:
Relevant code snippets:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { SpringBootClass.class })
public class databaseTests{
#Before
public void setup() throws LiquibaseException, SQLException {
Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(dataSource.getConnection()));
Liquibase liquibase = new Liquibase("db/changelog/db.changelog-master.yaml", new FileSystemResourceAccessor("src/main/resources/"),database );
liquibase.dropAll();
liquibase.update("test");
}
..
}
#SpringBootApplication
#Import({ DataSourceConfig.class, HibernateConfig.class, OauthConfig.class })
#EnableConfigurationProperties
public class SpringBootClass {
..
}
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.6.RELEASE</version>
<!-- <liquibase.version>3.3.5</liquibase.version> -->
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<scope>test</scope>
</dependency>
If you want your tests to consume application.properties you need to run them as a Spring Boot application. Your use of #ContextConfiguration means that you're currently running them as a vanilla Spring Framework application. Replace the #ContextConfiguration annotation with #SpringApplicationConfiguration.
Should have RTFM...
from spring boot documentation
ConfigFileApplicationContextInitializer is an
ApplicationContextInitializer that can apply to your tests to load
Spring Boot application.properties files. You can use this when you
don’t need the full features provided by
#SpringApplicationConfiguration.
#ContextConfiguration(classes = Config.class,
initializers = ConfigFileApplicationContextInitializer.class)
Changing my config to use the initializer worked.
Related
This question already has answers here:
Should SpringRunner be used in Spring Boot with Junit 5
(3 answers)
Closed last year.
My micro-service project based on spring-boot framework and all my unit test running with spring runner.
#RunWith(SpringRunner.class)
adding this annotations, imports the following library:
import org.springframework.test.context.junit4.SpringRunner;
How can I set my test classes to run with junit5 ?
Using JUnit Jupiter (aka JUnit 5) no longer requires ˋ #RunWith(SpringRunner.class)ˋ since this is a JUnit 4 mechanism. With recent versions of Spring/Spring Boot JUnit 5 support comes out of the box eg through using ˋspring-boot-starter-testˋ.
I recommend to exclude dependencies on JUnit 4 in your Maven/Gradle file to make confusing JUnit 4 and 5 features less likely.
Here’s an article that shows the basics: https://howtodoinjava.com/spring-boot2/testing/junit5-with-spring-boot2/
Remove JUnit4 from your build Path.
For example :
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Application.class)
#TestPropertySource(locations = "classpath:application-local.properties")
public class MyTest {
#Before
public void setUp() {
...
}
#Test
public void testMethod() {
Assert.assertTrue(...);
}
}
will become
#SpringBootTest(classes = Application.class)
#TestPropertySource(locations = "classpath:application-local.properties")
public class MyTest {
#BeforeEach
public void setUp() {
...
}
#Test
public void testMethod() {
Assertions.assertTrue(...);
}
}
Spring 2.4 seems to include JUnit 5 and make it the default out of the box.
Besides updating #RunWith(SpringJUnit4ClassRunner.class) to #ExtendWith(SpringExtension.class) I had to add the following to build.gradle for the tests to actually run:
test {
useJUnitPlatform {}
}
This last step may have been due to JUnit 4 being a dependency of one of my dependencies, but every other thing I read didn't suggest this was needed.
The first annotation #RunWith(SpringRunner.class) is used to provide a bridge between Spring Boot test features and JUnit. SpringRunner.class enables full support of spring context loading and dependency injection of the beans in the tests. #SpringBootTest create ApplicationContext tests through SpringApplication that will be utilized in our tests. It bootstraps the entire container since the embedded server and creates a web environment.
In our test, we can mimic the real web environment setting it as RANDOM_PORT that also loads WebServerApplicationContext. The embedded server is started and listen to on a random port.
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {YourPackage.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class YourClassTest {
#LocalServerPort
private int port;
#Autowired
TestRestTemplate restTemplate;
HttpHeaders headers = new HttpHeaders();
#ParameterizedTest
#JsonFileSource(resources = "/param.json")
void createBusinessEntity(JsonObject object){
....
}
}
#LocalServerPort annotation provides us the injected HTTP port that got allocated at runtime. It is a convenient alternative for #Value("${local.server.port}").
To access a third-party REST service inside a Spring application we use the Spring RestTemplate or TestRestTemplate the convenient alternative that is suitable for integration tests by injecting it in our test class. With spring-boot-starter-test dependency in our project, we can access to "TestRestTemplate" class in runtime.
In our test method, we are using the junit-json-params , a Junit 5 library that provides annotations to load data from JSON Strings or files in parameterized tests. We also annotated the method with #ParameterizedTest annotation to complement the library bellow. It is used to signal the annotated method is a parameterized test method. That method must not be private or static. They also must specify at least one ArgumentsProvider via #ArgumentsSource or a corresponding composed annotation.
Our #ArgumentsSource a JSON file #JsonFileSource(resources = "param.json") we put inside the test.resources package. #JsonFileSource lets you use JSON files from the classpath. It supports single objects, arrays of objects and JSON primitives.
The JSON object retrieved from the file is bound to the method params "object" that it is converted to a POJO object, in this case, our entity model.
In the Pom.xml we must import these libraries...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>com.vaadin.external.google</groupId>
<artifactId>android-json</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>net.joshka</groupId>
<artifactId>junit-json-params</artifactId>
<version>5.5.1-r0</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>${mockito.version}</version>
</dependency>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>${junit-jupiter.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
Take a look at these articles that a post on DZone and my blog where you can access a complete sample and explanation step by step how to test spring boot microservice using Junit 5.
https://dzone.com/articles/microservices-in-publish-subscribe-communication-u
https://www.jeevora.com/2019/11/18/publish-subscribe-messaging-systems/
I am new to spring boot. Spring boot has default properties file located in /src/main/resource folder with name application.properties. Now I want not to use the default property.
Suppose if I put two properties file:
1. demo1.properties
2. demo2.properties
How will be those two properties file referred in spring boot?
I am trying to use #PropertySource in main class but it is not working. Is there any other way?
This is my main class::
#SpringBootApplication
#ComponentScan("com.wiley.dnb.controller")
#PropertySource("classpath:log4j.properties")
#PropertySource("classpath:services.properties")
public class DNBMain {
public static void main(String[] args) {
// TODO Auto-generated method stub
SpringApplication.run(DNBMain.class, args);
}
}
Thanks in advance.
You need spring profiles!
Profiles help to have different application configuration for different environments.
At startup of your program, you choose which profile/configuration to use.
Here is a tutorial on this subject:http://www.springboottutorial.com/spring-boot-profiles
Add this dependency;
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
And add #PropertySource("classpath:application.properties") into your configuration Class.
You could annotate a configuration class with :
#PropertySource({"classpath:demo1.properties", "classpath:demo2.properties"})
to add properties in the Spring environment.
For example :
#SpringBootApplication
#PropertySource({"classpath:demo1.properties", "classpath:demo2.properties"})
public class MyApplication { ...}
Of course these properties file have to be located in the classpath at runtime.
I have a spring boot application that reads a value from a property from application.properties file in the Spring Boot Application. I want to use it as a switch and need to be able to change it during run time so that the code will switch as per the value configured to get the desired output.
As of now it is requiring a restart of the application. Here is what I am using:
#Configuration
#RefreshScope
#PropertySource("classpath:application.properties")
#Service
public class MyServiceImpl implements MyService {
#Value("${enabled}")
private boolean SWITCH_ENABLED;
if (SWITCH_ENABLED==true) {
// code for switch when true
}
else {
// code for switch is false
}
I have the following properties in the application.properties :
enabled=true
The value is not getting refreshed and takes effect only after restart. I tried using the spring-boot-actuator as well.
To take advantage of the #RefreshScope annotation you need to send a refresh to your app. You can spring-cloud-context to your classpath which adds /refresh and /env endpoints.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
<version>1.3.4.RELEASE</version>
</dependency>
Then after you change application.properties or application.yml you can POST to /refresh which will reload the properties. Example:
curl -X POST http://localhost:8080/refresh
Updated
My class listed below (ServiceDiscoveryConfiguration) is never being utilized. Even if I remove the #EnableDiscoveryClient to attempt to completely avoid the setup, it still attempts to connect to Consul.
The only thing that worked for me was removing the Consul Maven depdency completely:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-all</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
What can I do to prevent Consul for running for unit tests if not through the profile and annotation setup?
Original
I have an application using Spring Consul.
I have a class set up to enable discovery like this:
#Profile ("!" + Profiles.UNIT_TEST)
#Configuration
#EnableDiscoveryClient
public class ServiceDiscoveryConfiguration {
}
This should be disabling the Consul portion, if I am not mistaken. The base test class (it's an abstract shared between all of my unit tests) is setup up with the following annotations. This is where I think the problem is.
#SpringBootTest (classes = Service.class)
#WebAppConfiguration
#TestExecutionListeners (...)
#DirtiesContext
#ActiveProfiles (Profiles.UNIT_TEST)
#Test (...)
public abstract class AbstractBootTest extends AbstractTestNGSpringContextTests {
// ...
}
When I execute my tests I get:
Caused by: com.ecwid.consul.transport.TransportException:
java.net.ConnectException: Connection refused
This leads me to believe that the profile activation is not working or my syntax using the ! operator on the #Profile specification is not doing what I thought it was supposed to be doing. The root execution class itself has basic annotations including a #ComponentScan annotation that I know has the appropriate packages being scanned.
Assistance?
You can disable via
#TestPropertySource(properties = {"spring.cloud.consul.config.enabled=false"})
if you have bootstrap.properties file in your project, you should create bootstrap.properties file under test/resources:
spring.application.name=<service-name>
spring.cloud.bus.enabled=false
spring.cloud.discovery.enabled=false
spring.cloud.consul.enabled=false
spring.cloud.consul.config.enabled=false
This will disable consul integration in tests
Add below property in your application.properties file under test/resources
spring.cloud.discovery.enabled=false
spring.cloud.consul.enabled=false
spring.cloud.consul.config.enabled=false
This will disable consul integration while testing your application
The problem is that if you have spring-consul in the classpath it will try to auto-configure it anyway
The profile annotation is correct
#Profile ("!" + Profiles.UNIT_TEST)
the profile activation looks ok, also
#ActiveProfiles (Profiles.UNIT_TEST)
You wrote you are using ComponentScan, that is important, because #Profile annotation on a bean is ignored, if the bean is instantiated by a #Bean annotated method. May be you check again, to see, this does not happen ?
To narrow down the problem you can try :
set a breakpoint in the constructor of ServiceDiscoveryConfiguration, to see if it is instantiated or not
remove #EnableDiscoveryClient to see if this is really the cause of your problems
I have a multi-module Spring-Boot project.
I was wondering how I can set up integration testing just to test Spring Data JPA repositories? The following approach fails with this exception:
HV000183: Unable to load 'javax.el.ExpressionFactory'. Check that you have the EL dependencies on the classpath.
Since this module does not depend on the web module, there is no web application that can be started.
#RunWith(SpringJUnit4ClassRunner.class)
#IntegrationTest
#SpringApplicationConfiguration(classes = TestConfiguration.class)
class CardInfoRepositoryIT {
#Autowired CardInfoRepository cardInfoRepository;
#Test
void testLoadData() {
assert cardInfoRepository.findAll().size() == 1
}
}
As Marten mentioned, #IntegrationTest should only be used when you need to test against the deployed Spring Boot application (e.g., deployed in an embedded Tomcat, Jetty, or Undertow container). So if your goal is to test your repository layer in isolation, you should not use #IntegrationTest.
On the other hand, if your tests require specific Spring Boot functionality (in contrast to standard Spring Framework functionality, semantics, and defaults), then you will in fact want to annotate your test class with #SpringApplicationConfiguration instead of #ContextConfiguration. The reason is that #SpringApplicationConfiguration preconfigures the SpringApplicationContextLoader which is specific to Spring Boot.
Furthermore, if you want your repository layer integration tests to run faster (i.e., without the full overhead of Spring Boot), you may choose to exclude configuration classes annotated with #EnableAutoConfiguration since that will auto-configure every candidate for auto-configuration found in the classpath. So, for example, if you just want to have Spring Boot auto-configure an embedded database and Spring Data JPA (with Hibernate as the JPA provider) along with entity scanning, you could compose your test configuration something like this:
#Configuration
#EnableJpaRepositories(basePackageClasses = UserRepository.class)
#EntityScan(basePackageClasses = User.class)
#Import({ DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
public class TestRepositoryConfig {}
And then use that configuration in your test class like this:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = TestRepositoryConfig.class)
#Transactional
public class UserRepositoryTests { /* ... */ }
Regards,
Sam
p.s. You might find my answer to the following, related question useful as well: Disable security for unit tests with spring boot
I resolved this by having the following test config class.
#Configuration
#EnableAutoConfiguration
#ComponentScan
#PropertySource("classpath:core.properties")
class TestConfiguration {
}
core.properties is also used by the main application and it contains datasource information. #IntegrationTest annotation can be removed on the test class.
I also added the following to the module as dependencies:
testRuntime 'javax.el:javax.el-api:2.2.4'
testRuntime 'org.glassfish.web:javax.el:2.2.4'