Using different Spring properties for integration

2020-07-18 08:53发布

问题:

I am testing with Selenium a web application developed with Spring to check that the web application displays the right stuff for the user and that he's able to do everything that is in the specification.

The other developers are using a fake Hibernate database in memory (HSQLDB) for unit testing. I have to use the real DB used by the program for testing, obviously. The JDBC parameters for the Spring application context are loaded by Spring at runtime (or compile time for building the WAR file). Spring use properties found by org.springframework.beans.factory.config.PropertyPlaceholderConfigurer to configure the application context for the webapp and the tests, and the XML configuration files are shared by the tests and the webapp.

The properties need to be different depending on the Maven profile, unit tests or integration tests.

I tried several approaches, without success:

  • developing my own DAO's using lower-level SQL queries. It's a real waste of time and solution of last resort. Because of the foreign key constraints and database model changes, and given that the application has a pretty solid (unit-tested) set of DAO's, it's really the dumbest option.
  • using Maven filters and define the JDBC properties there. The problem is that the properties are shared between the main application and the unit tests, because the tomcat:redeploy goal include unit tests. The application then cannot connect to the real DB.
  • having different properties in different folders. Spring doesn't care at all about the additional resources defined in the profiles' Surefire configuration, either with testResources or resources. The strange thing is that this approach works perfectly well for having different JDBC parameters for each environment in the main app. We have several folders in src/main/resources which contains properties overriding the default properties in src/main/resources. It just doesn't work the same way for src/test/resources. I don't even know how I could find the cause of this behavior.
  • have Spring loading different property files based on user-defined Maven parameters. The same properties are used for the main app and the unit tests. Spring also complain when it cannot find the properties files (forcing me to create directories with empty files just to get the build completing).

Why is the current build configuration, with the developer profile (developer, test server...) + the test profile (unit tests) activated at the same time running and the properties not overriding one another? Because Maven will make Spring look at src/test/resources when the unit tests are launched and src/main/resources when the build goal is launched. Unfortunately, there is no default configuration for integration tests like this.

回答1:

The way we do it is base the selection of the properties file off a variable, so property place holder in spring looks like this:

<context:property-placeholder location="classpath:db.${TARGET_ENV}.properties" />

And then you have a choice of defining TARGET_ENV as an environment variable or passing it to maven using -DTARGET_ENV=...



回答2:

For unit tests you may have the property file with same name as in production which will override production one since it's earlier in classpath. e.g. you may have production properties at src/main/resources/my.properties and overriding file for unit tests at src/test/resources/my.properties.

The good practice is to have a separate property file with environment settings only (hosts/ports) and other application-specific property files that are using values from environment-specific one. Then environment specific file is the only file you need to change. For integration testing you may also have specific property file in the classpath.

Also, there should be no environment-specific settings inside production artifacts. They should be located separately.

One more thing you may try is to use spring @Profiles. But using them you put some non-production settings in your code which is a bad practice.