Testing Quickstart

1. Add ebean-test-config as a test dependency

<dependency>
  <groupId>io.ebean.test</groupId>
  <artifactId>ebean-test-config</artifactId>
  <version>11.26.1</version>
  <scope>test</scope>
</dependency>

2. Add application-test.yml

Add into src/test/resources a application-test.yml configuration file that we use for testing.

ebean:
  test:
    platform: h2 #, h2, postgres, mysql, oracle, sqlserver
    ddlMode: dropCreate # none | dropCreate | create | migration | createOnly | migrationDropCreate
    dbName: myapp

We can modify this test configuration to control what DDL is executed (create-all.sql or migrations) and the database platform we want to test against (potentially using docker).

ebean-test-config will take care of:

  • Properties to control DDL generation and execution
  • Docker container setup and execution based on the database platform
  • JDBC Datasource properties (matching the database docker container)
  • Register a current user and tenant provider if not already specified (to ease testing with @Who properties etc)

ddlMode

Mode Description
dropCreate Drop and then create all the tables etc. Most commonly used mode.
none Do not run any DDL. Useful if we want to run 1 particular test without any DDL change.
migration Run the DB migration. Good for testing migrations run as expected.
migrationDropCreate Run the DB migration but first delete the database first ensuring the migration runs against a new database.
create Run the create-all.sql DDL script but delete and recreate the database first.
createOnly Run the create-all.sql DDL script but without recreating the database first.

platform

Platform Description
h2 Run using in-memory H2 database.
url: jdbc:h2:mem:{databaseName}
driver: org.h2.Driver
postgres Run against Postgres docker DB.
port: 6432
password: test
url: jdbc:postgresql://localhost:{port}/{databaseName}
driver: org.postgresql.Driver
image: postgres:{version}
postgis Run against Postgres Postgis docker DB.
port: 7432
password: test
url: jdbc:postgresql_lwgis://localhost:{port}/{databaseName}
driver: org.postgis.DriverWrapperLW
image: mdillon/postgis:{version}
mysql Run against MySql docker DB.
port: 4306
password: test
url: jdbc:mysql://localhost:{port}/{databaseName}
driver: com.mysql.jdbc.Driver
image: mysql:{version}
sqlserver Run against SqlServer docker DB with the following defaults.
port: 1433
password: SqlS3rv#r
url: jdbc:sqlserver://localhost:{port};databaseName={databaseName}
driver: com.microsoft.sqlserver.jdbc.SQLServerDriver
image: microsoft/mssql-server-linux:{version}
oracle Run against Oracle docker DB.
port: 1521
password: test
url: jdbc:oracle:thin:@localhost:{port}:XE
driver: oracle.jdbc.driver.OracleDriver
image: sath89/oracle-12c:{version}
sqlite Run using Sqlite database.
url: jdbc:sqlite:{databaseName}
driver: org.sqlite.JDBC
isolationlevel: read_uncommitted

Docker / ebean-test-docker

For all the platforms apart from H2 and Sqlite this will automatically:

  • Start a docker container (if necessary)
  • Wait for the container to be ready
  • Create the database and user setting any permissions as necessary
  • When ready allow the tests to run

We can see/review what is occurring by increasing the logging for io.ebean.docker to TRACE. When we do that we can see log messages like:

15:15:02.232 [main] INFO  io.ebean.EbeanVersion - ebean version: 11.26.1


## PROPERTIES FILE(S)

15:15:02.284 [main] INFO  i.e.config.properties.LoadContext - loaded properties from [application.yml, application-test.yml]


## DOCKER COMMANDS

15:15:02.537 INFO  io.ebean.docker.commands.Commands - Container ut_postgres running with port:6432 db:test_ex user:test_ex mode:Create shutdown:
15:15:02.538 DEBUG io.ebean.docker.commands.Commands - docker exec -i ut_postgres pg_isready -h localhost -p 5432
15:15:02.645 DEBUG io.ebean.docker.commands.Commands - docker exec -i ut_postgres psql -U postgres -c select datname from pg_database
15:15:02.753 DEBUG io.ebean.docker.commands.Commands - docker exec -i ut_postgres psql -U postgres -c select rolname from pg_roles where rolname = 'test_ex'
15:15:02.871 DEBUG io.ebean.docker.commands.Commands - docker exec -i ut_postgres psql -U postgres -c select 1 from pg_database where datname = 'test_ex'
15:15:02.960 DEBUG io.ebean.docker.commands.Commands - create database extensions hstore,pgcrypto
15:15:02.960 DEBUG io.ebean.docker.commands.Commands - docker exec -i ut_postgres psql -U postgres -d test_ex -c create extension if not exists hstore
15:15:03.058 DEBUG io.ebean.docker.commands.Commands - docker exec -i ut_postgres psql -U postgres -d test_ex -c create extension if not exists pgcrypto
15:15:03.143 DEBUG io.ebean.docker.commands.Commands - waitForConnectivity ut_postgres ...
15:15:03.143 DEBUG io.ebean.docker.commands.Commands - checkConnectivity on ut_postgres ...
15:15:03.190 DEBUG io.ebean.docker.commands.Commands - connectivity confirmed for ut_postgres
15:15:03.190 DEBUG io.ebean.docker.commands.Commands - Container ut_postgres ready with port 6432


## FOR TESTING ... set a current user and tenant provider

15:15:03.194 [main] INFO  i.e.t.c.provider.ProviderAutoConfig - for testing purposes a current user and tenant provider has been configured. Use io.ebean.test.UserContext to set current user and tenant in tests.


## SELECTED PLATFORM

15:15:03.239 [main] INFO  o.a.datasource.pool.ConnectionPool - DataSourcePool [db] autoCommit[false] transIsolation[READ_COMMITTED] min[2] max[200]
15:15:03.277 [main] INFO  io.ebean.internal.DefaultContainer - DatabasePlatform name:db platform:postgres


## EXECUTE DDL

15:15:03.618 [main] INFO  io.ebean.DDL - Executing extra-dll - 0 statements
15:15:03.618 [main] INFO  io.ebean.DDL - Executing db-drop-all.sql - 26 statements
15:15:03.649 [main] DEBUG io.ebean.DDL - executing 1 of 26 alter table if exists address drop constraint if exists fk_address_country_code
15:15:03.651 [main] DEBUG io.ebean.DDL - executing 2 of 26 drop index if exists ix_address_country_code
...
15:15:03.701 [main] INFO  io.ebean.DDL - Executing db-create-all.sql - 28 statements
15:15:03.701 [main] DEBUG io.ebean.DDL - executing 1 of 28 create table address ( id                            bigserial not null, line1...
15:15:03.709 [main] DEBUG io.ebean.DDL - executing 2 of 28 create table contact ( id                            bigserial not null, first_n...
...
15:15:03.841 [main] INFO  io.ebean.DDL - Executing extra-dll - 1 statements
15:15:03.842 [main] DEBUG io.ebean.DDL - executing 1 of 1 create or replace view order_agg_vw as select d.order_id as id, d.order_id as or...

Container startup

To startup the docker containers we hook into the Ebean lifecycle. This means that it will "just work" whether the tests are run from the IDE, maven, gradle or any build tool. In prior iterations the startup of docker containers was hooked specifically into the maven lifecycle but this proved to be less than ideal.

In general this is providing a similar experience to the one we have when using H2 database. That is, we bring up the database (if needed), setup the database, user, roles etc (if needed) get it ready for testing by running DDL ... and then run all tests.

Container shutdown

On developer machines we generally keep the docker container running. On a CI server we may want to stop the docker container after running all the tests. To do this we set shutdown to either stop (to just stop the container) or remove (to stop and remove the container).

ebean:
  test:
    shutdown: stop  # stop | remove
    platform: postgres # h2, postgres, mysql, oracle, sqlserver
    ddlMode: dropCreate # none | dropCreate | create | migration | createOnly | migrationDropCreate
    dbName: myapp

Not using Docker

If we don't want to start and run a Docker container but instead test against some other existing database we can do that via setting useDocker: false.

The below configuration runs against an existing Postgres database. Typically when not using docker we need to set the username, password and url to appropriate values.

When we are using useDocker: false the database and user are expected to already exist along with permissions (and Postgres extension).

ebean:
  test:
    useDocker: false  ## DO NOT USE DOCKER
    platform: postgres # h2, postgres, mysql, oracle, sqlserver
    ddlMode: dropCreate # none | dropCreate | create | migration | createOnly | migrationDropCreate
    dbName: test
    postgres:
      username: test
      password: test
      url: jdbc:postgresql://localhost:5432/test

Current User and Tenant Providers

ebean-test-config will automatically register a current user provider and a current tenant provider. These are only set if you don't set them yourself.

What this means is that without doing anything we can use @WhoCreated / @WhoModified in tests and via io.ebean.test.UserContext we can set current user and tenant in tests.

// set the current userId which will be put
// into 'WhoCreated' and 'WhoModified' properties

UserContext.setUserId("U1");

Postgis

Refer to Postgis docker example.