During my unit tests using Spock and Testcontainers, the JpaRepository is not functioning properly and is not being wired correctly. This issue persists even in non-integration tests.
As suggested in another discussion, I attempted to resolve the issue by adding the spock-spring dependency to my pom.xml file. It didn't work.
No matter the scenario, the repository consistently returns as null in all instances.
An example:
@Testcontainers
class PostgresTestContainer extends Specification {
@Autowired
private PersonRepository personRepository
@Shared
PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer("postgres:12-alpine")
.withDatabaseName("test")
.withUsername("test")
.withPassword("test")
def "waits until postgres accepts jdbc connections"() {
when: "querying the database"
def response = personRepository.findAll()
then: "result is returned"
response == 0
}
}
CodePudding user response:
The database is being initialized using PostgresContainer
and Testcontainers
annotation. However your test infrastructure doesn't know about the database. If using spring boot, then few things are missed
- Add
SpringBootTest
orDataJpaTest
annotation on top of the class. This way the spring application context is created with the right classes andPersonRepository
will be injected - Switch to
static postgresContainer = new PostgreSQLContainer("postgres:12-alpine")
@Shared
PostgreSQLContainer <?> cassandra = cassandraContainer
- In order to make use of the database provided by Testcontainers, add
@DynamicPropertySource
static void registerProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgresContainer::getJdbcUrl);
registry.add("spring.datasource.username", postgresContainer::getUsername);
registry.add("spring.datasource.password", postgresContainer::getPassword);
}
CodePudding user response:
I would suggest to separate the container setup like the following:
PostgresEnvrionement
@Testcontainers
public class PostgresEnvironment {
@Container
public static PostgreSQLContainer postgreSQLContainer = PostgresTestContainer.getInstance();
}
PostgresTestContainer
public class PostgresTestContainer extends PostgreSQLContainer<PostgresTestContainer> {
public static final String IMAGE_VERSION = "postgres:13.5";
public static final String DATABASE_NAME = "test";
private static PostgresTestContainer container;
private PostgresTestContainer() {
super(IMAGE_VERSION);
}
public static PostgresTestContainer getInstance() {
if (container == null) {
container = new PostgresTestContainer().withDatabaseName(DATABASE_NAME);
}
return container;
}
@Override
public void start() {
super.start();
System.setProperty("DB_URL", container.getJdbcUrl());
System.setProperty("DB_USERNAME", container.getUsername());
System.setProperty("DB_PASSWORD", container.getPassword());
}
@Override
public void stop() {
}
}
In your test file extend the PostgresEnvironment
@ActiveProfiles("test")
@SpringBootTest(classes = MainSpringBootApp.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class AssembleEventRepositoryIntegrationTest extends PostgresEnvrionement{
// autowire jpa
// write tests
}
in your application-test.yml
file in the resources section under the test directory
spring:
datasource:
password: ${DB_USERNAME}
username: ${DB_PASSWORD}
driver-class-name: org.postgresql.Driver
url: ${DB_URL}
Also make sure that your main application.yml
file that is being used once launching your application (not in for running your tests) matches the same syntax as your test profile.