I have the following configuration for Spock class which is responsible for running integration tests.
#ContextConfiguration(classes = AccountService.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
#Sql(executionPhase= Sql.ExecutionPhase.BEFORE_TEST_METHOD,scripts="classpath:/integration-tests/clear-tables.sql")
#AutoConfigureEmbeddedDatabase
class AccountControllerIntegrationSpec extends Specification
{
.....
}
I have two profiles. The purpose is to active use set of annotations :
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
#Sql(executionPhase= Sql.ExecutionPhase.BEFORE_TEST_METHOD,scripts="classpath:/integration-tests/clear-tables.sql")
when I run docker-test profile.
When I run profile test I would like to use only #AutoConfigureEmbeddedDatabase (postgress embedded database for tests).
Profile test-docker should use real database from other container.
Profile test should use embedded database Postgress when I run tests locally on machine.
How can I configure during startup spring to choose databaseSource ?
When I add both annontations each time Embedded Postgres is only active even if test-docker profile is active I tried to set scope of dependency for embedded Postgres set differently for profiles. But it did not help.
Related
I have some unit test classes in my project that I want to test with mvn test. But whenever I run the command an instance of spring boot starts and opens database connections.
I´m running these tests in a server that doesn´t have access to a database, and none of my tests uses one. I just one to execute the tests as the IDE does.
I think one of them could help you
1 - Disable all tests
mvn clean install -DskipTests
2 - Prepare your test for switching
#ExtendWith(SpringExtension.class)
#EnabledIf(expression = "${tests.spring.enabled:true}")
if you pass -Dtests.spring.enabled= false or true will disable test
3 - Point your test to other configuration
#ExtendWith(SpringExtension.class)
#TestPropertySource(locations = "classpath:application-${spring.profiles.active:test}.properties")
this way you could connect your application into a local database
4 - Change your tests
Use mocks to turn your integration tests into a unit tests or component tests with no connections
The problem I had was an empty class with #SpringBootTest annotation. After deleting it the tests works without spring interfering.
everyone。When I was writing junit, I found that #ActiveProfiles corresponds to my resource directory。
I don’t understand how spring boot loads resource files,And why if I don’t specify #ActiveProfiles which application file is read by default?
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#SpringBootTest(classes = Application.class)
#ActiveProfiles("test")
public class NewTutorGroupIaoTest {
}
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#SpringBootTest(classes = Application.class)
#ActiveProfiles("test")
public class NewTutorGroupIaoTest {
}
project directory:
project
- src
- main
- java
- resource
- test
- java
- resource
If you mark classes with #Profile("test"), you can ensure they're loaded (into the ApplicationContext) by activating the test profile - either with #ActiveProfiles("test"), spring.profiles.active=test, or a number of other ways. Classes can be excluded with #Profile("!test")
More details here: https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-profiles
Also, by activating a profile, you may also activate a properties file to be picked up... You may also have files in your project like:
application.properties
application-default.properties
application-test.properties
If you have application.properties present as well as application-test.properties, application.properties forms the base config, and application-test.properties will overwrite any existing properties and may also supply additional configuration values.
If you supply/specify no profile, the default profile is activated. This will result in application.properties + application-default.properties being combined (as before).
You will see in the logs which profile is activated very near the beginning of the Spring log output.
Liquibase does not run when I execute my Cucumber tests, although works fine for application and unit tests.
I have a suite of cucumber-spring tests, testing a spring-boot application.
I have recently introduced Liquibase to the application, which runs fine when I run the application or the unit tests, but does not get run when I run my cucumber tests, either from a RunCukesTest Junit class or from the cucumber-cli.
The correct application.properties files get loaded in all cases, and I do nothing special to get Liquibase to run in the standard application and tests. It is enabled by default, and I have tried forcing enabled, but with no luck.
I have tried setting a SpringLiquibase bean in the tests, but cucumber-spring does not like this, as it does not allow further #Configuration classes.
The Liquibase jar is available on the classpath, and referencing a Liquibase type compiles fine in the cucumber steps.
The only property I set is :
spring.liquibase.change-log=classpath:db/changelog/db.changelog-master.xml
My Cucumber test class has the signature:
#Ignore
#SpringBootTest(classes = {Application.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
public class SpringConfig extends SpringBootBaseIntegrationTest implements En {
in application.properties. I have tried setting this for Cucumber application.properties also with no change.
Liquibase should run my changelog files as per standard application launch.
Given a spring boot gradle module named "md-core" with a Spring application runner and a PostgresDbConfig to connect it to the DB.
The app runs perfectly fine and resolves the properties from the "application.yml" file in the #Config.
#Value("${db.default.pool.size}")
Integer maxPoolSize;
Now, a separate module called "integrationtests" tries to launch the Spring Boot Runner in the "md-core" module.
#ContextConfiguration(classes = {MdCore.class})
#RunWith(SpringJUnit4ClassRunner.class)
public class GivenTest
The test launches the "md-core" Spring runner, but when trying to resolve the properties in the #Config, it does not find any properties.
I've tried directly resolving the "application.yml" in the test. It does not send the properties over to the "md-core" module. Any attempt of adding the "application.yml" properties in the test resolves them to the test file, but does not send them over when the "md-core" module is accessed.
Are there any definitions which should be given in the test via annotations or in the gradle build files?
The classpath when launching the test does not contain the "md-core" resources location, only the classes.
Could this be a reason? If yes, how can the resources be referenced in the classpath of the gradle build files?
I apologize for any mistakes or incomplete information, this post is being written at the end of a work day, hoping there will be answers by morning.
Given this situation, the solution to use the application.properties file for the integration test is the simple addition of initializers = ConfigFileApplicationContextInitializer.class in the #ContextConfiguration annotation of the Test class:
#ContextConfiguration(
initializers = ConfigFileApplicationContextInitializer.class,
classes = {SomeApp.class})
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
public class SomeIntegrationTest {
#Test
public void testTheIntegration() {
// some integration tests here
}
}
Answer also documented in a post on my blog and initially found less detailed on another stackoverflow question.
In our Spring web applications, we use the Spring bean profiles to differentiate three scenarios: development, integration, and production. We use them to connect to different databases or set other constants.
Using Spring bean profiles works very well for the changing the web app environment.
The problem we have is when our integration test code needs change for the environment. In these cases, the integration test loads the application context of the web app. This way we don't have to redefine database connections, constants, etc. (applying the DRY principle).
We setup our integration tests like the following.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = ["classpath:applicationContext.xml"])
public class MyTestIT
{
#Autowired
#Qualifier("myRemoteURL") // a value from the web-app's applicationContext.xml
private String remoteURL;
...
}
I can make it run locally using #ActiveProfiles, but this is hard-coded and causes our tests to fail on the build server.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = ["classpath:applicationContext.xml"])
#ActiveProfiles("development")
public class MyTestIT
{ ... }
I also tried using the #WebAppConfiguration hoping that it might somehow import the spring.profiles.active property from Maven, but that does not work.
One other note, we also need to configure our code so that developers can run the web app and then run the tests using IntelliJ's test runner (or another IDE). This is much easier for debugging integration tests.
As other people have already pointed out, you can opt to use Maven to set the spring.profiles.active system property, making sure not to use #ActiveProfiles, but that's not convenient for tests run within the IDE.
For a programmatic means to set the active profiles, you have a few options.
Spring 3.1: write a custom ContextLoader that prepares the context by setting active profiles in the context's Environment.
Spring 3.2: a custom ContextLoader remains an option, but a better choice is to implement an ApplicationContextInitializer and configure it via the initializers attribute of #ContextConfiguration. Your custom initializer can configure the Environment by programmatically setting the active profiles.
Spring 4.0: the aforementioned options still exist; however, as of Spring Framework 4.0 there is a new dedicated ActiveProfilesResolver API exactly for this purpose: to programmatically determine the set of active profiles to use in a test. An ActiveProfilesResolver can be registered via the resolver attribute of #ActiveProfiles.
Regards,
Sam (author of the Spring TestContext Framework)
I had a similar problem: I wanted to run all of my integration tests with a default profile, but allow a user to override with a profile that represented a different environment or even db flavor without having to change the #ActiveProfiles value. This is doable if you are using Spring 4.1+ with a custom ActiveProfilesResolver.
This example resolver looks for a System Property, spring.profiles.active, and if it does not exist it will delegate to the default resolver which simply uses the #ActiveProfiles annotation.
public class SystemPropertyActiveProfileResolver implements ActiveProfilesResolver {
private final DefaultActiveProfilesResolver defaultActiveProfilesResolver = new DefaultActiveProfilesResolver();
#Override
public String[] resolve(Class<?> testClass) {
if(System.getProperties().containsKey("spring.profiles.active")) {
final String profiles = System.getProperty("spring.profiles.active");
return profiles.split("\\s*,\\s*");
} else {
return defaultActiveProfilesResolver.resolve(testClass);
}
}
}
And in your test classes, you would use it like this:
#RunWith(SpringJUnit4ClassRunner.class)
#ActiveProfiles( profiles={"h2","xyz"},
resolver=SystemPropertyActiveProfileResolver.class)
public class MyTest { }
You can of course use other methods besides checking for the existence of a System Property to set the active profiles. Hope this helps somebody.
If you want to avoid hard-coding the profile you may want to use the system property spring.profiles.active and set it to whatever you need in that particular environment e.g. we have "dev", "stage" and "prod" profiles for our different environments; also we have a "test", "test-local" and "test-server" profiles for our testing.
Remember that you can have more than one profile in that system property by using a list of comma-separated values e.g. "test,test-qa".
You can specify system properties in a maven project in the maven surefire plugin or passing them like this:
mvn -DargLine="-DpropertyName=propertyValue"
As #ElderMael mentioned you could use the argLine property of maven surefire plugin. Often when I need to run all the test with different specific Spring profiles I define additional maven profile. Example:
<profiles>
<profile>
<id>foo</id>
<dependencies>
<!-- additional dependencies if needed, i.e. database drivers ->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-Dspring.profiles.active=foo</argLine>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
With that approach you could easily run all the test with activated profile by maven command:
mvn clean test -Pfoo
The #ActiveProfile annotation is good but sometimes we need to run all the test with activated specific profiles and with hard-coded #ActiveProfile parameters it is a problem.
For example: by default integration test with H2 in-memory db, but sometimes you want to run test on the "real" database. You could define that additional maven profile and define Jenkins job. With SpringBoot you could also put additional properties to test/resources with name application-foo.yml (or properties) and those properties will be taken into account to.
there are many faces to this problem.
in my case, a simple addition to build.gradle already helped:
test { systemProperties = System.properties }