@EntityListeners Injection + jUnit Testing

Leonardo Beal :

I use @EntityListeners to make operations before I save in my Db and after I load. Inside my Listener class I make a call to an Ecryptor (which needs to fetch info from configuration file), so the encryptor can't be called statically and need to be injected in my Listener. Right?

Well, injections in EntityListeners can't be done straight away, but you have some methods to do that, like using SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); or even the method showed here. https://guylabs.ch/2014/02/22/autowiring-pring-beans-in-hibernate-jpa-entity-listeners/

Cool, the problem is: None of the solutions support unit testing! When running tests that encryptor I had injected in my model Listener is always null.

Here SpringBeanAutowiringSupport does not inject beans in jUnit tests There is a solution to create this context and pass to a instantiated object, but it does not solve my problem since I have the "Injection" to add to it.

Any way to create a context in my tests and somehow pass it to my listeners? If not, any way I can create a static method to my Encryptor and still have access to the Environment API to read my properties?

Package Listener:

public class PackageListener{
   @Autowired
   Encryptor encryptor;

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

My test

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

Package service

  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;
    }
    ...
vsoni :

You can create a DemoApplicationContextInitializer class to store the appliationContext reference in a static property in your main 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);
    }
}

Then you can access the context in your entity listener

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

And to make this work in your junit test, just add the initializer in your test like this ...

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

It works without any issue in my environment. Hope it will be helpful to you too.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=436398&siteId=1