Skip to content
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

Allow to use Testcontainers with @AutoConfigureTestDatabase #19038

Closed
snicoll opened this issue Nov 17, 2019 · 5 comments
Closed

Allow to use Testcontainers with @AutoConfigureTestDatabase #19038

snicoll opened this issue Nov 17, 2019 · 5 comments
Labels
status: superseded An issue that has been superseded by another theme: testing Issues related to testing type: enhancement A general enhancement

Comments

@snicoll
Copy link
Member

snicoll commented Nov 17, 2019

Follow-up of this limitation reported on SO, it would be nice if users were able to configure the URL that @AutoConfigureTestDatabase uses. Right now if they want a specific dialect or any other extra parameter, they have to switch off our support to configure things manually.

@snicoll snicoll added the type: enhancement A general enhancement label Nov 17, 2019
@snicoll snicoll added this to the 2.x milestone Nov 17, 2019
@snicoll
Copy link
Member Author

snicoll commented Jan 16, 2020

We've spent some time discussing this feature and we're willing to investigate a support of testcontainers rather which would provide all the necessary flexibility.

@snicoll snicoll changed the title Allow to configure the JDBC url that @AutoConfigureTestDatabase uses Allow to use TestContainers with @AutoConfigureTestDatabase Jan 16, 2020
@snicoll snicoll added the status: pending-design-work Needs design work before any code can be developed label Jan 16, 2020
@snicoll
Copy link
Member Author

snicoll commented Mar 4, 2020

Now that we have r2dbc support, we should also take that use case into account so that the ConectionFactory points to a database replaced via this mechanism.

@wilkinsona
Copy link
Member

wilkinsona commented Jul 5, 2021

I've been experimenting a little bit in this area. I have a test class like this:

@JdbcTest
@AutoConfigureTestDatabase(replace = Replace.NONE)
@Testcontainers(disabledWithoutDocker = true)
@Import(SomeRepository.class)
@Sql(scripts = "data.sql")
class SomeRepositoryTests {

	@Container
	private static final PostgreSQLContainer<?> postgresqlContainer = new PostgreSQLContainer<>("postgres:13.2")
			.withDatabaseName("example");

	@Autowired
	private SomeRepository someRepository;

        // @Test methods

I've then got a context customizer factory and a context customizer that turns each JdbcDatabaseContainer field into a DataSource bean:

/**
 * A {@link ContextCustomizerFactory} that returns a
 * {@link JdbcDatabaseContainerContextCustomizer} when {@link JdbcDatabaseContainer} is on
 * the classpath and the test class has one or more static fields of that type.
 *
 * @author Andy Wilkinson
 */
class JdbcDatabaseContainerContextCustomizerFactory implements ContextCustomizerFactory {

	@Override
	public ContextCustomizer createContextCustomizer(Class<?> testClass,
			List<ContextConfigurationAttributes> configAttributes) {
		if (ClassUtils.isPresent("org.testcontainers.containers.JdbcDatabaseContainer", testClass.getClassLoader())) {
			Set<Field> jdbcDatabaseContainerFields = new HashSet<>();
			ReflectionUtils.doWithFields(testClass, (field) -> {
				if (Modifier.isStatic(field.getModifiers())
						&& JdbcDatabaseContainer.class.isAssignableFrom(field.getType())) {
					ReflectionUtils.makeAccessible(field);
					jdbcDatabaseContainerFields.add(field);
				}
			});
			if (!jdbcDatabaseContainerFields.isEmpty()) {
				return new JdbcDatabaseContainerContextCustomizer(jdbcDatabaseContainerFields);
			}
		}
		return null;
	}

}
/**
 * {@link ContextCustomizer} that registers a {@link DataSource} bean for each
 * {@link JdbcDatabaseContainer} field in the test class.
 *
 * @author Andy Wilkinson
 */
class JdbcDatabaseContainerContextCustomizer implements ContextCustomizer {

	private final Set<Field> jdbcDatabaseContainerFields;

	JdbcDatabaseContainerContextCustomizer(Set<Field> jdbcDatabaseContainerFields) {
		this.jdbcDatabaseContainerFields = jdbcDatabaseContainerFields;
	}

	@Override
	public void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
		for (Field field : this.jdbcDatabaseContainerFields) {
			JdbcDatabaseContainer<?> container = (JdbcDatabaseContainer<?>) ReflectionUtils.getField(field, null);
			BeanDefinition definition = new RootBeanDefinition(DataSource.class,
					() -> DataSourceBuilder.create(context.getClassLoader()).url(container.getJdbcUrl())
							.username(container.getUsername()).password(container.getPassword()).build());
			((BeanDefinitionRegistry) context.getBeanFactory()).registerBeanDefinition(field.getName(), definition);
		}
	}

}

I think this isn't too far off. I'd prefer it if @AutoConfigureTestDatabase(replace = Replace.NONE) wasn't necessary. If this context customization was done in Boot itself, we'd also need some way of opting in as it'd be too much for it to always happen. Perhaps a @TestDatabase annotation on the test's postgresqlContainer field?

The above isn't hugely Testcontainers-specific and I wonder if there may be some mileage in some general support for adding beans to the context or setting properties in the environment that are derived from static fields in a test class. It could be useful for #27151 as well, for example, with a mechanism that allows the JdbcDatabaseContainer to DataSource bean or org.neo4j.harness.Neo4j to spring.neo4j.* properties capability to be contributed.

@wilkinsona wilkinsona added the for: team-meeting An issue we'd like to discuss as a team to make progress label Jul 6, 2021
@wilkinsona wilkinsona added the theme: testing Issues related to testing label Jul 6, 2021
@wilkinsona wilkinsona removed the for: team-meeting An issue we'd like to discuss as a team to make progress label Jul 26, 2021
@philwebb philwebb modified the milestones: 2.x, 3.x Aug 19, 2022
@wilkinsona wilkinsona changed the title Allow to use TestContainers with @AutoConfigureTestDatabase Allow to use Testcontainers with @AutoConfigureTestDatabase May 31, 2024
@vpavic
Copy link
Contributor

vpavic commented Sep 18, 2024

This was perhaps made obsolete by #35253?

@wilkinsona
Copy link
Member

Yes, I think it was. Thanks, @vpavic.

@wilkinsona wilkinsona closed this as not planned Won't fix, can't repro, duplicate, stale Sep 19, 2024
@wilkinsona wilkinsona added status: superseded An issue that has been superseded by another and removed status: pending-design-work Needs design work before any code can be developed labels Sep 19, 2024
@wilkinsona wilkinsona removed this from the 3.x milestone Sep 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: superseded An issue that has been superseded by another theme: testing Issues related to testing type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

4 participants