java - How to initialize beans in proper order if some beans are present in test mode only? -


good day. spring boot app uses postgress database. tests uses h2 database. when running in non-test mode beans need initialized in order:

1) init datasource 2) init jpa beans 

when running in test mode need create , populate h2 database before jpa beans initialization:

1) init datasource 2) init datasourceinitializer 3) init jpa beans 

the problem jpa beans initialized before datasourceinitializer (step 3 precedes step 2) , test fails on missing tables (hibernate.hbm2ddl.auto=validate).

step 1

@configuration @enabletransactionmanagement public class datasourceconfig {      @primary     @bean     @configurationproperties(prefix = "datasource.runtime")     public datasource runtimedatasource() {         return datasourcebuilder.create().build();     } } 

step 2

@configuration @profile(profiles.integration_test) public class datasourcetestconfig {      @autowired     private resourceloader resourceloader;      @bean     public datasourceinitializer runtimedatasourceinitializer(@qualifier("runtimedatasource") datasource datasource) {         datasourceinitializer initializer = new datasourceinitializer();         initializer.setdatasource(datasource);         initializer.setdatabasepopulator(new resourcedatabasepopulator(                 resourceloader.getresource("classpath:runtime/schema.sql")         ));         return initializer;     } } 

step 3

@configuration @enabletransactionmanagement public class jpaconfig {      @autowired     private environment environment;      @autowired     @qualifier(value = "runtimedatasource")     private datasource runtimedatasource;      @primary     @bean     public localcontainerentitymanagerfactorybean runtimeentitymanagerfactory(entitymanagerfactorybuilder builder) {         return builder                 .datasource(runtimedatasource)                 .properties(hibernatesettings())                 .packages(                         "cz.adx.anx.car.cases.domain",                         "cz.adx.anx.car.lib.domain",                         "org.springframework.data.jpa.convert.threeten" // hibernate support java 8 date , time classes                 )                 .persistenceunit("runtimepersistenceunit")                 .build();     } } 

i need beans class datasourcetestconfig initialized before jpaconfig , after datasourceconfig in test mode. in non-test mode beans jpaconfig should initialized after datasourceconfig , beans datasourcetestconfig must omited. therefore cannot annotate class jpaconfig @dependson beans class datasourcetestconfig because class located in test packages , not present in non-test mode. duplicate config classes , make them conditional on profile don't feel comfortable solution. please, there better solution? in advance!

ps: app uses 2 databases/datasources shortened code above make easier read. i'm using spring boot 1.3.1.release.

update 1: tried use approach suggested @luboskrnac. placed annotation activeprofiles on integration test classes:

@activeprofiles("it") public abstract class integrationtest {...} 

and used annotation profile on relevant beans in class jpaconfig shown below:

@configuration @enabletransactionmanagement public class jpaconfig {      @autowired     private environment environment;      @autowired     @qualifier(value = "runtimedatasource")     private datasource runtimedatasource;      @autowired     @qualifier(value = "configdatasource")     private datasource configdatasource;      @profile("!it")     @bean(name = "runtimeentitymanagerfactory")     @dependson("runtimedatasource")     public localcontainerentitymanagerfactorybean runtimeentitymanagerfactory(entitymanagerfactorybuilder builder) {         return createruntimeentitymanagerfactory(builder);     }      @profile("it")     @bean(name = "runtimeentitymanagerfactory")     @dependson("runtimedatasourceinitializer")     public localcontainerentitymanagerfactorybean testruntimeentitymanagerfactory(entitymanagerfactorybuilder builder) {         return jpaconfig.createruntimeentitymanagerfactory(builder);     }      public localcontainerentitymanagerfactorybean createruntimeentitymanagerfactory(entitymanagerfactorybuilder builder) {         return builder             .datasource(runtimedatasource)             .properties(hibernatesettings())             .packages(                 "cz.adx.anx.car.cases.domain",                 "cz.adx.anx.car.lib.domain",                 "org.springframework.data.jpa.convert.threeten" // hibernate support java 8 date , time classes             )             .persistenceunit("runtimepersistenceunit")             .build();     } } 

and i'm creating transaction managers same way. because use 2 datasources (two different databases) use bean names in enablejparepositories annotation.

@configuration @enablejparepositories(         entitymanagerfactoryref = "runtimeentitymanagerfactory",         transactionmanagerref = "runtimetransactionmanager",         basepackages = "cz.adx.anx.car.lib.repository" ) public class jpacarlibrepositoryconfig { } 

so need non-test bean , test bean registered under same name. spring gives me exception:

org.springframework.beans.factory.nouniquebeandefinitionexception: no qualifying bean of type [javax.persistence.entitymanagerfactory] defined: expected single matching bean found 2: runtimeentitymanagerfactory 

any advices please?

i suggest drop considerations explicit bean creation ordering or bean dependencies.

simply populate database in test based on spring @sql annotation. test may this:

@runwith(springjunit4classrunner.class) @contextconfiguration @sql("/test-schema.sql") public class databasetests {      @test     public void emptyschematest {         // execute code uses test schema without test data     }      @test     @sql({"/test-schema.sql", "/test-user-data.sql"})     public void usertest {         // execute code uses test schema , test data     } } 

if you'll need swap datasource (e.g. using postgeresql in prod , h2 in tests), use spring @profile, @activeprofiles annotations.


Comments

Popular posts from this blog

routing - AngularJS State management ->load multiple states in one page -

python - GRASS parser() error -

Swift game error message -