2017-12-01 21 views
11

Tôi sử dụng @EntityListeners để thực hiện các thao tác trước khi tôi lưu trong Db và sau khi tải. Bên trong lớp Listener của tôi, tôi thực hiện cuộc gọi đến Ecryptor (cần lấy thông tin từ tệp cấu hình), vì vậy bộ mã hóa không thể được gọi tĩnh và cần được tiêm vào Trình nghe của tôi. Đúng?@EntityListeners Injection + jUnit Testing

Không thể thực hiện ngay việc tiêm trong EntityListeners, nhưng bạn có một số phương pháp để thực hiện điều đó, như sử dụng SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); hoặc thậm chí phương pháp được hiển thị ở đây. https://guylabs.ch/2014/02/22/autowiring-pring-beans-in-hibernate-jpa-entity-listeners/

Thật tuyệt, vấn đề là: Không có giải pháp nào hỗ trợ kiểm tra đơn vị! Khi chạy các kiểm tra mà bộ mã hóa mà tôi đã tiêm vào Trình nghe mô hình của mình luôn là null.

Ở đây SpringBeanAutowiringSupport does not inject beans in jUnit tests Có một giải pháp để tạo ngữ cảnh này và chuyển đến một đối tượng được khởi tạo, nhưng nó không giải quyết được vấn đề của tôi vì tôi có "Tiêm" để thêm vào nó.

Bất kỳ cách nào để tạo ngữ cảnh trong các bài kiểm tra của tôi và bằng cách nào đó sẽ chuyển ngữ cảnh đó cho người nghe của tôi? Nếu không, bất kỳ cách nào tôi có thể tạo một phương pháp tĩnh để mã hóa của tôi và vẫn có quyền truy cập vào API môi trường để đọc các thuộc tính của tôi?

Gói Thính giả:

public class PackageListener{ 
    @Autowired 
    Encryptor encryptor; 

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

thử nghiệm của tôi

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

dịch vụ trọn gói

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

Nếu nó là 'null' bạn không sử dụng ngữ cảnh. Kiểm tra của bạn làm cho tôi tự hỏi nếu bạn thậm chí sử dụng bối cảnh được tạo ra bởi các thử nghiệm (Tôi nghi ngờ nó nhìn vào những gì bạn đang làm trong thử nghiệm của bạn). –

+0

Cảm ơn nhận xét của bạn @ M.Deinum, tôi đang tạo ngữ cảnh bằng cách sử dụng '@ContextConfiguration (classes = {ApplicationConfiguration.class})' trong lớp 'BaseTest' của tôi. Tất cả các thao tác tiêm và cấu hình hoạt động đúng cách, ngoài 'Encryptor' (được gọi từ EntityListener) –

+0

Như đã nói, tôi nghi ngờ bạn đang thực sự sử dụng nó theo cách bạn đang có một dịch vụ ... –

Trả lời

0

Bạn có thể tạo một lớp DemoApplicationContextInitializer để lưu trữ tham chiếu appliationContext trong thuộc tính tĩnh trong lớp chính của bạn.

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

Sau đó, bạn có thể truy cập vào bối cảnh thực thể nghe bạn

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

Và để làm công việc này trong thử nghiệm junit của bạn, chỉ cần thêm initializer trong thử nghiệm của bạn như thế này ...

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

Nó hoạt động mà không có bất kỳ vấn đề nào trong môi trường của tôi. Hy vọng nó sẽ hữu ích cho bạn quá.

1

Để trả lời những gì bạn cần, bạn phải tạo 2 lớp sẽ thực hiện tất cả các cấu hình cần thiết.

Bạn phải tạo một testConfig với các chú thích tiếp theo:

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

Sau đó, nếu bạn muốn kết nối với cơ sở dữ liệu của bạn:

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

} 

Bây giờ bạn có nó tất cả các thiết lập, bạn chỉ cần để tạo thử nghiệm nhập cấu hình của bạn:

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

Bạn sẽ nhận được bối cảnh mùa xuân của mình nitialized với quyền truy cập vào tất cả các tài nguyên của bạn (MVC) Dịch vụ, DAO và Model.

+0

cảm ơn câu trả lời của bạn. Như tôi đã đề cập trong các ý kiến, tiêm làm việc hoàn hảo trong các bài kiểm tra của tôi. Vấn đề duy nhất của tôi là với Tiêm bên trong JPA EntityListener, khi chạy thử nghiệm. –