[英]Test configuration for Jpa auditing
I am trying to use Spring Data, Hibernate Envers and auditing in Spring Boot application.我正在尝试在 Spring Boot 应用程序中使用 Spring Data、Hibernate Envers 和审计。 I have configured AuditorAwareImpl
我已经配置了 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.现在我想为我的集成测试创建 AuditorAware。 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
.当我从
TestAuditingConfiguration
删除@EnableJpaAuditing
,它可以正常工作,但有一个例外 - 测试中的自动装配auditorAware
是来自TestAuditingConfiguration
一个,但另一方面用于审计是从AuditingConfiguration
使用的,因此result.getCreatedBy()
将返回Default auditor
result.getCreatedBy()
而不是Test auditor
result.getCreatedBy()
。 I read that for database integration tests should be used @DataJpaTest
annotation so I have changed it.我读到数据库集成测试应该使用
@DataJpaTest
注释,所以我已经改变了它。 Now with enabled @EnableJpaAuditing
on TestAuditingConfiguration
I received:现在在
@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
But after adding @Import(TestAuditingConfiguration.class)
it works as I excpected - result.getCreatedBy()
returns Test auditor
.但是在添加
@Import(TestAuditingConfiguration.class)
它按我的预期工作 - result.getCreatedBy()
返回Test auditor
result.getCreatedBy()
。 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.现在我真的很困惑 bean 在特定配置文件中的使用方式以及
@SpringBootTest
和@DataJpaTest
工作原理。 And why @Import
was important for @DataJpaTest
?为什么
@Import
是重要的@DataJpaTest
? Can anyone explain me that and what is preferred approach for database testing?谁能向我解释一下,什么是数据库测试的首选方法?
@DataJpaTest
is just a shortcut for a bunch of annotations. @DataJpaTest
只是一堆注释的快捷方式。 See https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTest.html见https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/autoconfigure/orm/jpa/DataJpaTest.html
It basically creates an ApplicationContext with only those beans regsitered that are relevant for JPA and Spring Data JPA.它基本上创建了一个 ApplicationContext,其中只包含与 JPA 和 Spring Data JPA 相关的那些 bean。
@SpringBootTest
creates a complete ApplicationContext with everything that is in your application. @SpringBootTest
使用应用程序中的所有内容创建一个完整的 ApplicationContext。 A lot of which it finds by scanning the class path for classes annotated with @Configuration
.它通过扫描用
@Configuration
注释的类的类路径来找到很多。
Therefore it will contain more "stuff" and in your case two @AuditorAware
beans.因此,它将包含更多“东西”,在您的情况下将包含两个
@AuditorAware
bean。 Which some "magic" inside Spring tries to create a jpaAuditingHandler
bean from. Spring 内部的一些“魔法”试图从中创建一个
jpaAuditingHandler
bean。 Since there are two AuditorAware
beans we end up with two beans of same name which is not acceptable.由于有两个
AuditorAware
bean,我们最终会得到两个同名的 bean,这是不可接受的。 See Spring boot 2.1 bean override vs. Primary .请参阅Spring boot 2.1 bean override vs. Primary 。 You Probably could enable bean overriding but that is not recommended.
您可能可以启用 bean 覆盖,但不建议这样做。
With @DataJpaTest
these configurations are not found and you end up with no AuditorAware
bean at all.使用
@DataJpaTest
这些配置,最终您根本没有AuditorAware
bean。 By importing the right configuration you get exactly the bean you want for your test and everything is happy.通过导入正确的配置,您可以准确地获得测试所需的 bean,一切都很顺利。
Which one is the better approach depends on how you run your tests and in the end is probably mostly a matter of taste.哪种方法更好取决于您如何运行测试,最终可能主要是品味问题。
I prefer using @DataJpaTest
for real systems, because it limits the effect of unrelated configurations on the database test.我更喜欢将
@DataJpaTest
用于真实系统,因为它限制了无关配置对数据库测试的影响。 It might also execute slightly faster although that is probably hardly noticeable for most test suites because in most applications I work with, most of the startup time was eaten by Hibernate which is required for database tests anyway and when you run multiple test having different configurations for different tests negatively affects caching.它的执行速度也可能稍快一些,尽管这对于大多数测试套件来说可能几乎不明显,因为在我使用的大多数应用程序中,大部分启动时间都被 Hibernate 占用了不同的测试会对缓存产生负面影响。
For small projects I prefer @SpringBootTest
since it is less to write and makes things simpler at least in the simple cases.对于小型项目,我更喜欢
@SpringBootTest
因为它编写起来更少,至少在简单的情况下使事情变得更简单。
move @EnableJpaAuditing
on another new file在另一个新文件上移动
@EnableJpaAuditing
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
@Configuration
@EnableJpaAuditing
public class JpaConfiguration {
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.