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
Post a Comment