8.6 KiB
##Hibernate Matrix Testing
Goal
Run hibernate-core functional tests on other DBs besides default H2 easily.
Well, although Functional Testing and Unit Testing are already well known in the developer world, but we ( hibernate team ) use a little different definition:
Unit Test
Test doesn't need DB involved or only the default DB (currently is H2) is fine, then we call it is a unit test.
Functional Test
Test which is used to verify a hibernate function and needs to make sure this function works fine on all DBs.
Just to be clear, in hibernate codebase, most tests we have are functional tests by this definition.
And all hibernate functional tests are also unit tests, since they are also supposed to pass on the default DB (H2).
MatrixTestingPlugin
Since Hibernate Core has moved to Gradle from Maven, so we created a gradle plugin, called MatrixTestingPlugin, to run hibernate functional tests on the DB matrix (this is why it is called MatrixTestingPlugin :).
The source of this plugin is here, this is used by Hibernate Core only right now, so this post is specific to hibernate core project only, hope one day we could denote it to the gradle community.
How to use this plugin
-
apply this plugin in your gradle build script (of course!)
In hibernate-core/hibernate-core.gradle we have this line:
apply plugin: org.hibernate.gradle.testing.matrix.MatrixTestingPlugin
-
SourceSet separation
Although it is possible to define a logical separation in Gradle (see this), I would like physical separation of unit tests and functional tests, so, we have this project structure:
localhost:hibernate-core stliu$ tree -L 3 ├── hibernate-core.gradle ├── src ├── main │ ├── antlr │ ├── java │ ├── javadoc │ ├── resources │ └── xjb ├── matrix │ └── java └── test ├── java └── resources
-
matrix/java
all functional tests go into this directory
-
test/java
all unit tests go into this directory
-
test/resources
all resources for functional tests and unit tests, yes, resource files in this directory are shared for both, so you don't need to copy one file to both place, for example, log4j.properties.
To make idea plugin (and eclipse plugin) works, we also have this defined in hibernate-core.gradle:
sourceSets { matrix { java { srcDir 'src/matrix/java' } resources { srcDir 'src/matrix/resources' } } } ideaModule { sourceDirs += file( '$buildDir/generated-src/antlr/main' ) testSourceDirs += file( 'src/matrix/java') testSourceDirs += file( 'src/matrix/resources') }
-
-
DB profile
A DB profile defines the JDBC driver and DB connection info ( and hibernate properties for this DB ) that hibernate should use to run functional tests on this DB.
A DB profile looks like this:
├── mysql50 │ ├── jdbc │ │ └── mysql-connector-java-5.1.9.jar │ ├── matrix.gradle │ └── resources │ └── hibernate.properties
There are two ways to define JDBC driver, as showed above, put the driver jar file into
jdbc
directory, or usematrix.gradle
file, below is something you should put into yourmatrix.gradle
file:jdbcDependency "mysql:mysql-connector-java:5.1.17"
As you can see, just add the driver's GAV into
jdbcDependency
configuration, then MatrixTestingPlugin will look it up from maven repository defined in thebuild.gradle
and add it to thetestCompile
scope.For DB connection info, you should add it into
resources/hibernate.properties
(if you have Redhat VPN access, you can use the DB maintained by JBoss QA and get the DB connection automatically through DB Allocator, see below).NOTE: this
hibernate.properties
will overrides the one inhibernate-core/test/resources/hibernate.properties
if same property name defined in both place.And, the DB profile name is the directory name, in this example, it is mysql50.
The default DB profile location is in
hibernate-core/databases
directory, but you can also reallocate it to another place by using system propertyhibernate-matrix-databases
, see below for more details.
Matrix Tasks
Once you have DB profiles defined, you could run gradle tasks --all
, this will list all tasks you can use.
For example, there will be a matrix
task, which depends on all of other matrix_${profile_name}
tasks, each DB profile has a matrix_${profile_name}
task, so if you want to run hibernate functional tests on all DB profiles, then just call gradle matrix
or if you want to run them on mysql only, then gradle mysql50
.
In this case ( run gradle matrix
or its sub-task gradle matrix_${profile_name}
), only tests in src/matrix/java
will be ran, and hibernate.properties
come from your db profile/resources/hibernate.properties
(and test/resources/hibernate.properties
).
Matrix test results are in target/matrix/${profile_name}/test-results
.
But, there is also a test
task, this task runs all tests, both src/matrix/java
and src/test/java
, with src/test/resources
on default DB (as above said, all functional tests are also unit tests).
Unit test results are in target/test-results
, so if you run test
task, all test results are in here, instead of target/matrix/${profile_name}/test-results
, just as normal.
Configuration Properties
There are two way to pass a system property to gradle build:
1. The original java way, -Dxxx=yyy
2. Add it to ${user.home}/.gradle/gradle.properties with a 'systemProp' prefix, like 'systemProp.xxx=yyy'
-
hibernate-matrix-databases
This property is used to define the location of DB profile container.
Accept value: absolute path of DB profile container directory. -
hibernate-matrix-ignore
This property is used to ignore some DB profiles (or all of them), so if you run
matrix
, the ignored profile matrix task won't be run.Accept value : all or
{profile name1},
{profile name2},${profile name3}
DB Allocator (JBoss internally, VPN required)
For users who has access to JBoss QA lab (need Redhat VPN), here is a better way to run matrix tests, you don't need to have a DB instance on your side, but you can use DB instance in JBoss QA Lab.
And the connection info can be queried from DB Allocator automatically.
This feature is disabled by default, to enable it, you need this system property
-
hibernate-matrix-dballcoation
Accept value: all or
{profile name1},
{profile name2},${profile name3}
For example, if you want to run matrix test on postgresql84, you can use this command
./gradlew clean test matrix_postgresql84 -Dhibernate-matrix-dballocation=postgresql84
what does this command do actually?
1. test
run 'src/test/java' on default H2, test results in 'target/test-results'
run 'src/matrix/java' on default H2, test results in 'target/test-results'
2. query postgresql 84 db instance connection info
3. run 'src/matrix/java' on postgresql 84 with 'databases/postgresql84/matrix.gradle' defined jdbc driver and 'databases/postgresql84/resources/hibernate.properties' and postgresql84 db instance connection info (this info will override those defined in hibernate.properties), test results in 'target/matrix/postgresql84/results'
Some DBs need we tweak url with some configurations after get it from DB allocator, so, we can use this system property:
-
hibernate-matrix-dballocation-url-postfix-${dbname}
for example:
`-Dhibernate-matrix-dballocation-url-postfix-sybase155="?SQLINITSTRING=set quoted_identifier on&DYNAMIC_PREPARE=true"`
-
hibernate-matrix-dballocation-requestee This property is used to define the DB Allocator requester name, default is hibernate