2017-12-01 31 views
11

Dbに保存する前とロードした後で、@EntityListenersを使用して操作を行います。 Listenerクラスの中でEcryptor(設定ファイルから情報を取得する必要があります)を呼び出すため、暗号化プログラムを静的に呼び出すことができず、Listenerに注入する必要があります。右?@EntityListeners注入+ jUnitテスト

まあ、EntityListenersの注入はすぐにはできませんが、SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);やここに示した方法を使用するなど、いくつかの方法があります。 https://guylabs.ch/2014/02/22/autowiring-pring-beans-in-hibernate-jpa-entity-listeners/

クールで問題は次のとおりです。いずれのソリューションもユニットテストをサポートしていません。私がモデルListenerに注入した暗号化器を実行するテストは、常にnullです。

ここでSpringBeanAutowiringSupport does not inject beans in jUnit testsこのコンテキストを作成してインスタンス化されたオブジェクトに渡すソリューションがありますが、追加する「注入」があるので問題は解決しません。

私のテストでコンテキストを作成して何とかそれをリスナーに渡す方法はありますか? もしそうでなければ、私は自分の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; 
} 

Encryptorは:

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; 
    } 
    ... 
+0

「null」の場合は、コンテキストを使用していません。あなたのテストでは、テストで作成されたコンテキストを使用しているのかどうか疑問に思っています(テストで何をしているのかは分かりません)。 –

+0

あなたのコメントのためにありがとう@ M.Deinum、私は私の 'BaseTest'クラスで' @ContextConfiguration(classes = {ApplicationConfiguration.class}) 'を使ってコンテキストを作成しています。 'Encryptor'(EntityListenerから呼び出されたもの)を除いて、すべての注入と設定が正常に動作します –

+0

私が実際にあなたがサービスを取得している方法でそれを使用しているのか疑問に思っています... –

答えて

0

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 { 
... 
} 

私の環境では問題なく動作します。それがあなたにも役立つことを願っています。

1

必要なものに答えるには、必要なすべての設定を行う2つのクラスを作成する必要があります。あなたは、データベースと接続したい場合は、

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

を:あなたは、次の注釈とともにtestConfigを作成する必要が

@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 {...} 

私はあなたのスプリングコンテキストiを取得しますすべてのリソース(MVC)サービス、DAOおよびモデルへのアクセスでニアライズされています。

+0

あなたの答えに感謝します。私がコメントで述べたように、注射は私のテストでは完全に機能します。私の唯一の問題は、テストを実行しているときに、JPA EntityListener内のインジェクションにあります。 –