I am trying to use Spring Data, Hibernate Envers and auditing in Spring Boot application. I have configured AuditorAwareImpl
public class AuditorAwareImpl implements AuditorAware<String> {
@Override
public Optional<String> getCurrentAuditor() {
return Optional.of("Default auditor");
}
}
and configuration class for it.
@Configuration
@EnableJpaAuditing(auditorAwareRef = "auditorProvider")
public class AuditingConfiguration {
@Bean
public AuditorAware<String> auditorProvider() {
return new AuditorAwareImpl();
}
}
Now I would like to create AuditorAware for my Integration tests. I have created new configuration class with test auditor
@Configuration
@Profile("test")
@EnableJpaAuditing(auditorAwareRef = "testAuditorProvider")
public class TestAuditingConfiguration {
@Bean
@Primary
public AuditorAware<String> testAuditorProvider() {
return () -> Optional.of("Test auditor");
}
}
And when I try to write my integration test like this
@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("test")
public class AuditingApplicationTests {
@Autowired
private AuditorAware<String> auditorAware;
@Autowired
private MovieRepository movieRepository;
@Test
public void testCurrentAuditor() {
String currentAuditor = auditorAware.getCurrentAuditor().get();
assertEquals("Test auditor", currentAuditor);
}
@Test
public void movieRepositoryTest() {
Movie movie = new Movie("Movie");
movieRepository.save(movie);
List<Movie> movies = movieRepository.findAll();
Movie result = movies.get(0);
assertEquals("Test auditor", result.getCreatedBy());
}
}
I am getting this error:
Caused by: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'jpaAuditingHandler' defined in null: Cannot register bean definition [Root bean: class [org.springframework.data.auditing.AuditingHandler]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null] for bean 'jpaAuditingHandler': There is already [Root bean: class [org.springframework.data.auditing.AuditingHandler]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null] bound.
When I remove @EnableJpaAuditing
from TestAuditingConfiguration
it works fine with one exception - autowired auditorAware
in test is one from TestAuditingConfiguration
but on the other hand for auditing is used from AuditingConfiguration
so result.getCreatedBy()
will return Default auditor
instead of Test auditor
. I read that for database integration tests should be used @DataJpaTest
annotation so I have changed it. Now with enabled @EnableJpaAuditing
on TestAuditingConfiguration
I received:
org.springframework.beans.factory.UnsatisfiedDependencyException: Unsatisfied dependency expressed through field 'auditorAware'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.data.domain.AuditorAware<java.lang.String>' available: expected at least 1 bean which qualifies as autowire candidate
But after adding @Import(TestAuditingConfiguration.class)
it works as I excpected - result.getCreatedBy()
returns Test auditor
. So finally my test class looks like:
@RunWith(SpringRunner.class)
@DataJpaTest
@ActiveProfiles("test")
@Import(TestAuditingConfiguration.class)
public class AuditingApplicationTests {
@Autowired
private AuditorAware<String> auditorAware;
@Autowired
private MovieRepository movieRepository;
@Test
public void testCurrentAuditor() {
String currentAuditor = auditorAware.getCurrentAuditor().get();
assertEquals("Test auditor", currentAuditor);
}
@Test
public void movieRepositoryTest() {
Movie movie = new Movie("Movie");
movieRepository.save(movie);
List<Movie> movies = movieRepository.findAll();
Movie result = movies.get(0);
assertEquals("Test auditor", result.getCreatedBy());
}
}
Now I am really confused how beans are used in specific profiles and how @SpringBootTest
and @DataJpaTest
works. And why @Import
was important for @DataJpaTest
? Can anyone explain me that and what is preferred approach for database testing?