Я использую @EntityListeners
для выполнения операций перед тем, как сохранить в своем Db и после загрузки.
Внутри класса Listener я делаю вызов Ecryptor
(который должен извлекать информацию из файла конфигурации), поэтому шифрование нельзя вызвать статически и нужно ввести в мой Listener. Правильно?
Ну, инъекции в EntityListeners не могут быть выполнены сразу, но у вас есть некоторые способы сделать это, например, используя SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
или даже метод, показанный здесь. https://guylabs.ch/2014/02/22/autowiring-pring-beans-in-hibernate-jpa-entity-listeners/
Прохладный, проблема в том, что ни одно из решений не поддерживает модульное тестирование! При запуске тестов, которые я ввел в мою модель, в качестве хранителя всегда есть null
.
Здесь SpringBeanAutowiringSupport не вставляет beans в тесты jUnit. Существует решение для создания этого контекста и перехода к экземпляру объекта, но он не решает мою проблему так как у меня есть "Инъекция", чтобы добавить к ней.
Любой способ создать контекст в моих тестах и каким-то образом передать его моим слушателям?
Если нет, каким-либо образом я могу создать статический метод для моего Encryptor и все еще иметь доступ к 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;
}
...
Ответ 1
Вы можете создать класс DemoApplicationContextInitializer
для хранения ссылки appliationContext
в статическом свойстве в вашем основном классе.
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 {
...
}
Он работает без каких-либо проблем в моей среде. Надеюсь, это будет полезно и вам.
Ответ 2
Чтобы ответить на то, что вам нужно, вам нужно создать 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) Services, DAO и Model.