@EntityListeners 注入 + jUnit 测试
@EntityListeners Injection + jUnit Testing
我在保存到我的 Db 之前和加载之后使用 @EntityListeners
进行操作。
在我的 Listener class 中,我调用了一个 Ecryptor
(需要从配置文件中获取信息),因此加密器不能静态调用,需要注入到我的 Listener 中。对吗?
嗯,EntityListeners 中的注入无法立即完成,但您可以使用一些方法来做到这一点,例如使用 SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
甚至此处显示的方法。 https://guylabs.ch/2014/02/22/autowiring-pring-beans-in-hibernate-jpa-entity-listeners/
太棒了,问题是:None 的解决方案支持单元测试!当 运行 测试我在我的模型监听器中注入的加密器总是 null
.
这里 SpringBeanAutowiringSupport does not inject beans in jUnit tests 有一个创建上下文并传递给实例化对象的解决方案,但它没有解决我的问题,因为我有 "Injection" 添加到它。
有什么方法可以在我的测试中创建上下文并以某种方式将其传递给我的听众?
如果没有,我可以通过任何方式为我的加密器创建一个静态方法,并且仍然可以访问环境 API 来读取我的属性?
包监听器:
public class PackageListener{
@Autowired
Encryptor encryptor;
@PrePersist
public void preSave(final Package pack){
pack.setBic(encryptor.encrypt(pack.getBic()));
}
...
我的测试
@Test
@WithuserElectronics
public void testIfCanGetPackageById() throws PackageNotFoundException{
Package pack = packagesServiceFactory.getPackageService().getPackage(4000000002L);
}
套餐服务
public Package getPackage(Long id) throws PackageNotFoundException{
Package pack = packageDao.find(id);
if (pack == null) {
throw new PackageNotFoundException(id);
}
return pack;
}
加密器:
public class Encryptor{
private String salt;
public Encryptor(String salt){
this.salt = salt;
}
public String encrypt(String string){
String key = this.md5(salt);
String iv = this.md5(this.md5(salt));
if (string != null) {
return encryptWithAesCBC(string, key, iv);
}
return string;
}
...
要满足您的需求,您必须创建 2 个 类 来完成所需的所有配置。
您必须使用以下注释创建一个 testConfig:
@Configuration
@ComponentScan(basePackages = { "yourPath.services.*",
"yourPath.dao.*" })
@EnableAspectJAutoProxy
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "yourPath.dao.entities",
entityManagerFactoryRef = "entityManagerFactory",
transactionManagerRef = "transactionManager",
repositoryBaseClass = Dao.class)
@Import({ DataSourceConfig.class }) //Explained below
public class TestConfig {
@Autowired
private DataSource dataSource;
@Bean
public List<String> modelJPA() {
return Collections.singletonList("es.carm.sms.ortopedia.entities");
}
@Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
@Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setPackagesToScan(modelJPA().toArray(new String[modelJPA().size()]));
entityManagerFactory.setDataSource(this.dataSource);
JpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
entityManagerFactory.setJpaVendorAdapter(jpaVendorAdapter);
return entityManagerFactory;
}
}
然后如果你想连接你的数据库:
@Configuration
public class DataSourceConfig {
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("oracle.jdbc.OracleDriver");
dataSource.setUrl("jdbc:oracle:thin:@ip:port:sid");
dataSource.setUsername("name");
dataSource.setPassword("pass");
return dataSource;
}
}
现在你已经设置好了,你只需要创建你的测试导入你的配置:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestConfig.class)
public class TestCase {...}
您将获得 spring 上下文初始化,可以访问所有资源 (MVC) 服务、DAO 和模型。
您可以创建一个 DemoApplicationContextInitializer
class 以将 appliationContext
引用存储在主 class.
的静态 属性 中
public class DemoApplicationContextInitializer implements
ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext ac) {
Application.context = ac;
}
}
@SpringBootApplication
public class Application {
public static ApplicationContext context;
public static void main(String[] args) throws Exception {
new SpringApplicationBuilder(Application.class)
.initializers(new DemoApplicationContextInitializer())
.run(args);
}
}
然后您可以在您的实体侦听器中访问上下文
public class PackageListener{
//@Autowired
Encryptor encryptor;
@PrePersist
public void preSave(final Package pack){
encryptor = Application.context.getBean(Encryptor.class);
pack.setBic(encryptor.encrypt(pack.getBic()));
}
}
要在您的 junit 测试中进行这项工作,只需像这样在您的测试中添加初始化程序...
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT, classes = Application.class)
@ContextConfiguration(classes = Application.class, initializers = DemoApplicationContextInitializer.class)
public class MyTest {
...
}
它在我的环境中没有任何问题。希望对你也有帮助。
我在保存到我的 Db 之前和加载之后使用 @EntityListeners
进行操作。
在我的 Listener class 中,我调用了一个 Ecryptor
(需要从配置文件中获取信息),因此加密器不能静态调用,需要注入到我的 Listener 中。对吗?
嗯,EntityListeners 中的注入无法立即完成,但您可以使用一些方法来做到这一点,例如使用 SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
甚至此处显示的方法。 https://guylabs.ch/2014/02/22/autowiring-pring-beans-in-hibernate-jpa-entity-listeners/
太棒了,问题是:None 的解决方案支持单元测试!当 运行 测试我在我的模型监听器中注入的加密器总是 null
.
这里 SpringBeanAutowiringSupport does not inject beans in jUnit tests 有一个创建上下文并传递给实例化对象的解决方案,但它没有解决我的问题,因为我有 "Injection" 添加到它。
有什么方法可以在我的测试中创建上下文并以某种方式将其传递给我的听众? 如果没有,我可以通过任何方式为我的加密器创建一个静态方法,并且仍然可以访问环境 API 来读取我的属性?
包监听器:
public class PackageListener{
@Autowired
Encryptor encryptor;
@PrePersist
public void preSave(final Package pack){
pack.setBic(encryptor.encrypt(pack.getBic()));
}
...
我的测试
@Test
@WithuserElectronics
public void testIfCanGetPackageById() throws PackageNotFoundException{
Package pack = packagesServiceFactory.getPackageService().getPackage(4000000002L);
}
套餐服务
public Package getPackage(Long id) throws PackageNotFoundException{
Package pack = packageDao.find(id);
if (pack == null) {
throw new PackageNotFoundException(id);
}
return pack;
}
加密器:
public class Encryptor{
private String salt;
public Encryptor(String salt){
this.salt = salt;
}
public String encrypt(String string){
String key = this.md5(salt);
String iv = this.md5(this.md5(salt));
if (string != null) {
return encryptWithAesCBC(string, key, iv);
}
return string;
}
...
要满足您的需求,您必须创建 2 个 类 来完成所需的所有配置。
您必须使用以下注释创建一个 testConfig:
@Configuration
@ComponentScan(basePackages = { "yourPath.services.*",
"yourPath.dao.*" })
@EnableAspectJAutoProxy
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "yourPath.dao.entities",
entityManagerFactoryRef = "entityManagerFactory",
transactionManagerRef = "transactionManager",
repositoryBaseClass = Dao.class)
@Import({ DataSourceConfig.class }) //Explained below
public class TestConfig {
@Autowired
private DataSource dataSource;
@Bean
public List<String> modelJPA() {
return Collections.singletonList("es.carm.sms.ortopedia.entities");
}
@Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
@Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setPackagesToScan(modelJPA().toArray(new String[modelJPA().size()]));
entityManagerFactory.setDataSource(this.dataSource);
JpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
entityManagerFactory.setJpaVendorAdapter(jpaVendorAdapter);
return entityManagerFactory;
}
}
然后如果你想连接你的数据库:
@Configuration
public class DataSourceConfig {
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("oracle.jdbc.OracleDriver");
dataSource.setUrl("jdbc:oracle:thin:@ip:port:sid");
dataSource.setUsername("name");
dataSource.setPassword("pass");
return dataSource;
}
}
现在你已经设置好了,你只需要创建你的测试导入你的配置:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestConfig.class)
public class TestCase {...}
您将获得 spring 上下文初始化,可以访问所有资源 (MVC) 服务、DAO 和模型。
您可以创建一个 DemoApplicationContextInitializer
class 以将 appliationContext
引用存储在主 class.
public class DemoApplicationContextInitializer implements
ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext ac) {
Application.context = ac;
}
}
@SpringBootApplication
public class Application {
public static ApplicationContext context;
public static void main(String[] args) throws Exception {
new SpringApplicationBuilder(Application.class)
.initializers(new DemoApplicationContextInitializer())
.run(args);
}
}
然后您可以在您的实体侦听器中访问上下文
public class PackageListener{
//@Autowired
Encryptor encryptor;
@PrePersist
public void preSave(final Package pack){
encryptor = Application.context.getBean(Encryptor.class);
pack.setBic(encryptor.encrypt(pack.getBic()));
}
}
要在您的 junit 测试中进行这项工作,只需像这样在您的测试中添加初始化程序...
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT, classes = Application.class)
@ContextConfiguration(classes = Application.class, initializers = DemoApplicationContextInitializer.class)
public class MyTest {
...
}
它在我的环境中没有任何问题。希望对你也有帮助。