Open sbrannen opened 3 years ago
I initially opened an issue about nested test support against Spring Data Commons. This was the wrong place since this is not a Spring Data issue but rather possibly a Spring Boot or Framework one.
I could not make nested tests work with Spring Data JPA 2.4.1 (Spring Boot 2.4.0). I also tried with the latest Spring Data Neo4j (in a private repository) with the same result.
You can find the sample JPA repository here with reproduction instructions: https://github.com/fbiville/spring-data-jpa-nested.
Thanks, @fbiville. I think this is a Spring Framework bug. As far as I can tell the @DynamicPropertySource
isn't being picked up by ActorTests
and MovieTests
. As a result, the spring.datasource.url
property isn't set so the DataSource
can't be created.
The tests pass and share a single context if the use of @DynamicPropertySource
is replaced with an equivalent ApplicationContextIntializer
:
package com.example.demo;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace.NONE;
import static org.springframework.test.context.NestedTestConfiguration.EnclosingConfiguration.INHERIT;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.NestedTestConfiguration;
import org.testcontainers.containers.MySQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import com.example.demo.DemoApplicationTests.PropertiesInitializer;
import com.example.demo.actors.Actor;
import com.example.demo.actors.ActorRepository;
import com.example.demo.movies.Movie;
import com.example.demo.movies.MovieRepository;
@Testcontainers
@DataJpaTest
@AutoConfigureTestDatabase(replace = NONE)
@NestedTestConfiguration(INHERIT)
@ContextConfiguration(initializers = PropertiesInitializer.class)
class DemoApplicationTests {
@Autowired
EntityManager entityManager;
@Container
private static final MySQLContainer<?> mysqlContainer = new MySQLContainer<>("mysql:5.7");
@Nested
class ActorTests {
@Autowired
ActorRepository actorRepository;
@BeforeEach
void prepareActors() {
Query query = entityManager.createQuery("DELETE FROM Actor");
query.executeUpdate();
entityManager.persist(actor("Emil Eifrem"));
}
@Test
void loads_actors() {
List<Actor> actors = actorRepository.findAll();
assertThat(actors).hasSize(1);
assertThat(actors.iterator().next().getName()).isEqualTo("Emil Eifrem");
}
private Actor actor(String name) {
Actor actor = new Actor();
actor.setName(name);
return actor;
}
}
@Nested
class MovieTests {
@Autowired
MovieRepository movieRepository;
@BeforeEach
void prepareMovies() {
Query query = entityManager.createQuery("DELETE FROM Movie");
query.executeUpdate();
entityManager.persist(movie("The Matrix"));
}
@Test
void loads_movies() {
List<Movie> movies = movieRepository.findAll();
assertThat(movies).hasSize(1);
assertThat(movies.iterator().next().getTitle()).isEqualTo("The Matrix");
}
private Movie movie(String title) {
Movie movie = new Movie();
movie.setTitle(title);
return movie;
}
}
static class PropertiesInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
TestPropertyValues.of("spring.datasource.url=" + mysqlContainer.getJdbcUrl(),
"spring.datasource.username=" + mysqlContainer.getUsername(),
"spring.datasource.password=" + mysqlContainer.getPassword(),
"spring.jpa.hibernate.ddl-auto=create").applyTo(applicationContext);;
}
}
}
@fbiville Can you please open a Spring Framework issue and comment here with a link to it so that @sbrannen can take a look?
Issue created: https://github.com/spring-projects/spring-framework/issues/26091. Sorry for reporting that issue against the wrong project twice 😅
Since #12470 has been resolved and due to the general support for automatically inheriting test configuration from enclosing classes for JUnit Jupiter
@Nested
tests in Spring Framework 5.3, it would be good to have more@Nested
tests in the Spring Boot test suite in order to verify the expected behavior for various Spring Boot Test annotations when using@Nested
test classes.Aside from tests that verify the default, inherited behavior, it would also be good to have a few dedicated tests that verify support for
@NestedTestConfiguration(OVERRIDE)
semantics for Spring Boot Test annotations.For Spring Framework, I added several such test classes in the
org.springframework.test.context.junit.jupiter.nested
package which may serve as inspiration.