2017-12-01 3 views
11

Ich benutze @EntityListeners, um Operationen vor dem Speichern in meinem Db und nach dem Laden zu machen. Innerhalb meiner Listener-Klasse rufe ich eine Ecryptor (die Informationen aus der Konfigurationsdatei abrufen muss), so dass der Verschlüssler nicht statisch aufgerufen werden kann und in meinen Listener injiziert werden muss. Recht?@EntityListeners Injection + jUnit Testen

Nun, Injektionen in EntityListeners können nicht sofort durchgeführt werden, aber Sie haben einige Methoden, wie SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); oder sogar die hier gezeigte Methode zu tun. https://guylabs.ch/2014/02/22/autowiring-pring-beans-in-hibernate-jpa-entity-listeners/

Cool, das Problem ist: Keine der Lösungen unterstützt Unit Testing! Wenn Tests ausgeführt werden, die ich in meinem Modell injiziert habe, ist der Listener immer null.

Hier SpringBeanAutowiringSupport does not inject beans in jUnit tests Es gibt eine Lösung, um diesen Kontext zu erstellen und an ein instanziiertes Objekt zu übergeben, aber es löst mein Problem nicht, da ich die "Injection" hinzufügen muss.

Kann ich einen Kontext in meinen Tests erstellen und irgendwie an meine Zuhörer weitergeben? Wenn nicht, kann ich eine statische Methode für meinen Encryptor erstellen und trotzdem Zugriff auf die Environment API haben, um meine Eigenschaften zu lesen?

Paket Zuhörer:

public class PackageListener{ 
    @Autowired 
    Encryptor encryptor; 

    @PrePersist 
    public void preSave(final Package pack){ 
     pack.setBic(encryptor.encrypt(pack.getBic())); 
    } 
    ... 

Mein Test

@Test 
@WithuserElectronics 
public void testIfCanGetPackageById() throws PackageNotFoundException{ 
    Package pack = packagesServiceFactory.getPackageService().getPackage(4000000002L); 
} 

Paketdienst

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

Wenn es "null" ist, verwenden Sie den Kontext nicht. Ihr Test lässt mich fragen, ob Sie sogar den Kontext verwenden, der durch den Test erstellt wurde (ich bezweifle, dass Sie sehen, was Sie in Ihrem Test machen). –

+0

Danke für Ihren Kommentar @ M.Deinum, ich erstelle einen Kontext mit '@ContextConfiguration (classes = {ApplicationConfiguration.class})' in meiner 'BaseTest' Klasse. Alle Injektionen und Konfigurationen funktionieren einwandfrei, abgesehen von dem "Encryptor" (vom EntityListener) –

+0

Wie gesagt, ich bezweifle, dass Sie das tatsächlich verwenden, indem Sie einen Service erhalten ... –

Antwort

0

Sie können eine DemoApplicationContextInitializer Klasse erstellen, um die appliationContext Referenz in einer statischen Eigenschaft in Ihrer Hauptklasse zu speichern.

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

Dann können Sie den Kontext, in Ihrem Unternehmen Zuhörer Zugang

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

Und diese Arbeit in Ihrem JUnit-Test zu machen, fügen Sie einfach den Initialisierer in Ihrem Test wie dieser ...

@RunWith(SpringRunner.class) 
@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT, classes = Application.class) 
@ContextConfiguration(classes = Application.class, initializers = DemoApplicationContextInitializer.class) 
public class MyTest { 
... 
} 

Es funktioniert ohne irgendein Problem in meiner Umgebung. Hoffe, es wird dir auch hilfreich sein.

1

Um zu antworten, was Sie brauchen, müssen Sie 2 Klassen erstellen, die alle notwendigen Konfigurationen durchführen.

Sie haben eine testConfig mit den nächsten Anmerkungen zu erstellen:

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

Dann, wenn Sie mit Ihrer Datenbank verbinden möchten:

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

} 

Jetzt haben Sie es alle eingerichtet, die Sie gerade benötigen Um Ihren Test zu erstellen, importieren Sie Ihre Konfigurationen:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(classes = TestConfig.class) 
public class TestCase {...} 

Sie werden Ihren Frühling Zusammenhang ich bekommen nitialisiert mit Zugriff auf alle Ihre Ressourcen (MVC) Services, DAO und Model.

+0

danke für deine antwort. Wie ich in den Kommentaren erwähnte, funktionieren Injektionen in meinen Tests perfekt. Mein einziges Problem ist mit den Injektionen innerhalb des JPA EntityListener, wenn Tests ausgeführt werden. –