Skip to content

Investigate convention based application.properties specifically for tests #38098

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
philwebb opened this issue Oct 27, 2023 · 6 comments
Open
Labels
type: enhancement A general enhancement
Milestone

Comments

@philwebb
Copy link
Member

Currently it can can be quite awkward to add an application.properties for tests that overrides only specific values of the one in src/main/java. Some folks resort to adding a profile specific property and enabling a profile in all their tests. Some mix .properties and .yaml so that both files load and some use import:.

It would be nice if we had an out-of-the-box solution.

In addition, we could try to address the concern mentioned in #5307 (comment) and provide a way for a global user specific test application.properties file to also be loaded.

@wilkinsona wilkinsona added the type: enhancement A general enhancement label Oct 30, 2023
@wilkinsona wilkinsona added this to the 3.x milestone Oct 30, 2023
@philwebb philwebb added the for: planning An issue we'd like to consider when planning our next release label May 24, 2024
@philwebb philwebb modified the milestones: 3.x, 3.4.x, 3.5.x Jun 17, 2024
@mhalbritter
Copy link
Contributor

mhalbritter commented Jan 21, 2025

I played around a bit and came up with this solution: https://github.com/mhalbritter/spring-boot/tree/mh/38098-investigate-convention-based-applicationproperties-specifically-for-tests

It adds a new applyTestProfile attribute to the @SpringBootTest annotation. It defaults to true, and will then automatically apply the test profile to the test context.

That way users can use an src/test/resources/application-test.properties to override values from the src/main/resources/application.properties.

WDYT?

@nosan
Copy link
Contributor

nosan commented Jan 21, 2025

I think a more generic approach could be applied here instead of using applyTestProfile.

For example:

@ActiveProfiles
public @interface SpringBootTest {

	/**
	 * The profiles to activate.
	 * @return profiles to activate.
	 * @since 3.5.0
	 */
	@AliasFor(annotation = ActiveProfiles.class)
	String[] profiles() default { "test" };

	

}
	@SpringBootTest(profiles = {}) // no profiles
        @SpringBootTest //  'test' profile
	@SpringBootTest( profiles = { "profile1", "profile2" }) // 'profile1' and  'profile2' 

The same idea could be applied to slice annotations such as @DataJpaTest.

main...nosan:38098

But it looks like it does not work with @ActiveProfiles:

@SpringBootTest(profiles = { "test1" })
@ActiveProfiles("test2")

assertThat(this.environment.getActiveProfiles()).containsOnly("test1", "test2");

Expecting String[]:
  ["test2"]
to contain only:
  ["test1", "test2"]
but could not find the following string(s):
  ["test1"]

java.lang.AssertionError: 
Expecting String[]:
  ["test2"]
to contain only:
  ["test1", "test2"]
but could not find the following string(s):
  ["test1"]

@sbrannen
Copy link
Member

@nosan,

@SpringBootTest(profiles = "test1")
@ActiveProfiles("test2")
class MyTests { /* ... */ }

When you declare @ActiveProfiles directly on the test class and as a meta-annotation (on @SpringBootTest), the Spring TestContext Framework only finds the first one, the one closest to the class, which is @ActiveProfiles("test2") in your example.

Please note that @ActiveProfiles is not a repeatable annotation. That's why only a single @ActiveProfiles is supported on a given test class.

However, @ActiveProfiles can be inherited from superclasses.

@nosan
Copy link
Contributor

nosan commented Jan 21, 2025

Thanks, @sbrannen

In that case, @SpringBootTest(profiles = ...) could be managed within SpringBootTestContextBootstrapper, similar to how applyTestProfile is handled.

private String[] getActiveProfiles(Class<?> testClass, String[] activeProfiles) {
		SpringBootTest annotation = getAnnotation(testClass);
		Set<String> profiles = new LinkedHashSet<>(Arrays.asList(activeProfiles));
		if (annotation != null) {
			profiles.addAll(Arrays.asList(annotation.profiles()));
		}
		return profiles.toArray(String[]::new);
	}

@mhalbritter mhalbritter added for: team-meeting An issue we'd like to discuss as a team to make progress and removed for: planning An issue we'd like to consider when planning our next release labels Jan 21, 2025
@wilkinsona
Copy link
Member

wilkinsona commented Jan 22, 2025

I wonder if we should keep #24688 in mind when looking at this. If you squint a bit, tests could be thought of as an extra "module" that adds to the application's usual properties.

@philwebb philwebb modified the milestones: 3.5.x, 3.x Feb 12, 2025
@philwebb philwebb removed the for: team-meeting An issue we'd like to discuss as a team to make progress label Feb 12, 2025
@ThomasVitale
Copy link

ThomasVitale commented Apr 7, 2025

In my library (see docs), I provide two profiles out-of-the-box that are enabled when running the application in development mode (dev) and when running tests (test). I made them configurable since different teams have different conventions (e.g. local instead of dev). Multiple profiles are also supported for both development and test modes. By doing this, I also solve the problem described in #42066

To achieve this, I relied on an ApplicationListener (code here). I don't know if it's the best way to solve this problem, but it works quite effectively.

The library is included in a project only for development and test, so there is no risk to include dev/test config in the final production artefact. For example, in Gradle:

dependencies {
  testAndDevelopmentOnly 'io.arconia:arconia-dev-tools'
}

Furthermore, the whole feature can be turned off via properties.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

6 participants