Тестовая конфигурация для аудита Jpa - PullRequest
0 голосов
/ 27 мая 2019

Я пытаюсь использовать Spring Data, Hibernate Envers и аудит в приложении Spring Boot. Я настроил AuditorAwareImpl

public class AuditorAwareImpl implements AuditorAware<String> {

    @Override
    public Optional<String> getCurrentAuditor() {
        return Optional.of("Default auditor");
    }
}

и класс конфигурации для него.

@Configuration
@EnableJpaAuditing(auditorAwareRef = "auditorProvider")
public class AuditingConfiguration {

    @Bean
    public AuditorAware<String> auditorProvider() {
        return new AuditorAwareImpl();
    }
}

Теперь я хотел бы создать AuditorAware для моих интеграционных тестов. Я создал новый класс конфигурации с аудитором теста

@Configuration
@Profile("test")
@EnableJpaAuditing(auditorAwareRef = "testAuditorProvider")
public class TestAuditingConfiguration {

    @Bean
    @Primary
    public AuditorAware<String> testAuditorProvider() {
        return () -> Optional.of("Test auditor");
    }

}

И когда я пытаюсь написать свой интеграционный тест, как это

@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());
    }
}

Я получаю эту ошибку:

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.

Когда я удаляю @EnableJpaAuditing из TestAuditingConfiguration, он отлично работает, за одним исключением - в тесте используется автонастройка auditorAware - из TestAuditingConfiguration, но с другой стороны для аудита используется AuditingConfiguration, поэтому result.getCreatedBy() будет вернуть Default auditor вместо Test auditor. Я прочитал, что для тестирования интеграции базы данных должна использоваться аннотация @DataJpaTest, поэтому я изменил ее. Теперь с включенным @EnableJpaAuditing на TestAuditingConfiguration я получил:

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

Но после добавления @Import(TestAuditingConfiguration.class) все работает как я ожидал - result.getCreatedBy() возвращает Test auditor. Итак, наконец, мой тестовый класс выглядит так:

@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());
    }

}

Теперь я действительно запутался, как бины используются в определенных профилях и как работают @SpringBootTest и @DataJpaTest. И почему @Import был важен для @DataJpaTest? Может кто-нибудь объяснить мне, что и какой предпочтительный подход для тестирования базы данных?

...