Skip to content

Commit

Permalink
Add a basic README and license
Browse files Browse the repository at this point in the history
  • Loading branch information
rnorth committed Apr 26, 2015
1 parent ccb2713 commit 1d229b6
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 1 deletion.
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2015 Richard North

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
128 changes: 128 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# Test Containers

Test Containers is a Java library aimed at making it easier to test components or systems that interact with databases and other containerized things. Compared with other approches, Test Containers is intended to achieve a better balance between compatibility, speed, and overhead of external management.

Test Containers uses Docker to provide lightweight, throwaway instances of real databases and web servers for use in your tests.

You can use TC to obtain a containerized database in one of two ways:

### JUnit @Rule/@ClassRule

This mode starts a container before your tests and tears it down afterwards. This technique is aimed at JUnit tests of isolated components that just need a database temporarily (e.g. DAO tests). Nginx web server containers are also supported currently.

### Specially modified JDBC URL

After making a very simple modification to your system's JDBC URL string, Test Containers will provide a disposable stand-in database that can be used without requiring modification to your application code. This is intended to be used for development or integrated testing, when you want consistent, repeatable behaviour without the overhead of managing an external database.

## Support

Test Containers currently supports:

* MySQL
* PostgreSQL
* nginx

Other container types can be added later. Note that at present, only Docker Official containers from the Docker Hub registry can be used - this needs to be fixed.

## Comparison with other approaches

### Database running on development/test machine

* **Pro:** Perhaps the easiest option to initially 'get working'
* **Con:** Every developer and test environment has to be configured the same way - but frequently isn't, leading to configuration drift and unexpected bugs.
* **Con:** Managing a consistent database state is hard and often ignored, leading to flaky tests and different behaviour across environments or developer machines.

### Database running in a VM (e.g. using Vagrant)

* **Pro:** If managed using configuration management tools, this is a strong way to ensure consistent configuration
* **Con:** Restoration of the DB to a clean state isn't well catered for, and again often ignored due to slowness and complexity.
* **Con:** Control of VM state has to be managed externally from the Java test process, creating more moving parts.

### Using an embedded database (e.g. H2)

* **Pro:** very fast creation and teardown of databases
* **Pro:** completely controlled within the Java test process, meaning no external moving parts
* **Con:** not fully compatible with the target production database, leading to risk and bugs found late in development.

### Using Docker directly (e.g. via Fig/Docker compose)

* **Pro:** full compatibility with target database
* **Con:** external orchestration of containers required; a Java test process cannot obtain new containers on demand for isolated testing.

## Usage

### Prerequisites

Docker or boot2docker (for OS X) must be installed on the machine you are running tests on.

### JUnit rule

Add a @Rule or @ClassRule to your test class, e.g.:

public class SimpleMySQLTest {
@Rule
public MySQLContainerRule mysql = new MySQLContainerRule();

Now, in your test code (or a suitable setup method), you can obtain details necessary to connect to this database:

* `mysql.getJdbcUrl()` provides a JDBC URL your code can connect to
* `mysql.getUsername()` provides the username your code should pass to the driver
* `mysql.getPassword()` provides the password your code should pass to the driver

Note that if you use @Rule, you will be given an isolated container for each test method. If you use @ClassRule, you will get on isolated container for all the methods in the test class.

### JDBC URL

As long as you have TestContainers on your classpath, you can modify regular JDBC connection URLs.

**Original URL**: `jdbc:mysql://somehostname:someport/databasename`

Insert `tc:` after `jdbc:` as follows. Note that the hostname, port and database name will be ignored; you can leave these as-is or set them to any value.

#### Using Test Containers:

`jdbc:tc:mysql://somehostname:someport/databasename`

*(Note: this will use the latest version of MySQL)*

#### Using Test Containers with a fixed version:

`jdbc:tc:mysql:5.6.23://somehostname:someport/databasename`

#### Using PostgreSQL:

`jdbc:tc:postgresql://hostname/databasename`

#### Using an init script

Test Containers can run an initscript after the database container is started, but before your code is given a connection to it. The script must be on the classpath, and is referenced as follows:

`jdbc:tc:mysql://hostname/databasename?TC_INITSCRIPT=somepath/init_mysql.sql`

This is useful if you have a fixed script for setting up database schema, etc.

#### Using an init function

Instead of running a fixed script for DB setup, it may be useful to call a Java function that you define. This is intended to allow you to trigger database schema migration tools. To do this, add TC_INITFUNCTION to the URL as follows, passing a full path to the class name and method:

`jdbc:tc:mysql://hostname/databasename?TC_INITFUNCTION=org.rnorth.testcontainers.jdbc.JDBCDriverTest::sampleInitFunction`

The init function must be a public static method which takes a `java.sql.Connection` as its only parameter, e.g.

public class JDBCDriverTest {
public static void sampleInitFunction(Connection connection) throws SQLException {
// e.g. run schema setup or Flyway/liquibase/etc DB migrations here...
}
...

## License

See [LICENSE](LICENSE).

## Attributions

This project includes a modified class (ScriptUtils) taken from the Spring JDBC project, adapted under the terms of the Apache license. Copyright for that class remains with the original authors.

## Copyright

Copyright (c) 2015 Richard North
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.google.common.io.Resources;
import com.spotify.docker.client.messages.Container;
import org.rnorth.testcontainers.containers.DatabaseContainer;
import org.rnorth.testcontainers.jdbc.ext.ScriptUtils;
import org.slf4j.LoggerFactory;

import javax.script.ScriptException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package org.rnorth.testcontainers.jdbc;
package org.rnorth.testcontainers.jdbc.ext;

import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
Expand All @@ -29,6 +29,9 @@
import java.util.List;

/**
* This is a modified version of the Spring-JDBC ScriptUtils class, adapted to reduce
* dependencies and slightly alter the API.
*
* Generic utility methods for working with SQL scripts. Mainly for internal use
* within the framework.
*
Expand Down

0 comments on commit 1d229b6

Please sign in to comment.