A collection of JUnit rules

JUnit4 rules for DBUnit and JPA/Hibernate

License

License

Categories

Categories

JUnit Unit Testing
GroupId

GroupId

org.codegeny
ArtifactId

ArtifactId

codegeny-junit
Last Version

Last Version

0.0.2
Release Date

Release Date

Type

Type

jar
Description

Description

A collection of JUnit rules
JUnit4 rules for DBUnit and JPA/Hibernate
Source Code Management

Source Code Management

https://github.com/codegeny/codegeny-junit

Download codegeny-junit

How to add to project

<!-- https://jarcasting.com/artifacts/org.codegeny/codegeny-junit/ -->
<dependency>
    <groupId>org.codegeny</groupId>
    <artifactId>codegeny-junit</artifactId>
    <version>0.0.2</version>
</dependency>
// https://jarcasting.com/artifacts/org.codegeny/codegeny-junit/
implementation 'org.codegeny:codegeny-junit:0.0.2'
// https://jarcasting.com/artifacts/org.codegeny/codegeny-junit/
implementation ("org.codegeny:codegeny-junit:0.0.2")
'org.codegeny:codegeny-junit:jar:0.0.2'
<dependency org="org.codegeny" name="codegeny-junit" rev="0.0.2">
  <artifact name="codegeny-junit" type="jar" />
</dependency>
@Grapes(
@Grab(group='org.codegeny', module='codegeny-junit', version='0.0.2')
)
libraryDependencies += "org.codegeny" % "codegeny-junit" % "0.0.2"
[org.codegeny/codegeny-junit "0.0.2"]

Dependencies

compile (2)

Group / Artifact Type Version
junit : junit jar 4.12
org.dbunit : dbunit Optional jar 2.5.3

provided (1)

Group / Artifact Type Version
org.apache.tomee : javaee-api jar 7.0

test (6)

Group / Artifact Type Version
org.hamcrest : hamcrest-library jar 1.3
com.h2database : h2 jar 1.4.193
org.hibernate : hibernate-entitymanager jar 5.0.10.Final
org.apache.tomee : openejb-core jar 7.0.1
org.apache.tomee : openejb-junit jar 7.0.1
org.apache.tomee : openejb-mockito jar 7.0.1

Project Modules

There are no modules declared in this project.

Build Status Code Coverage Code Analysis

codegeny-junit

A collection of JUnit rules (mainly for DBUnit and JPA) that I am using and wanted to share.

<dependency>
	<groupId>org.codegeny</groupId>
	<artifactId>codegeny-junit</artifactId>
	<version>0.0.1-SNAPSHOT</version>
</dependency>

<repositories>
	<repository>
		<id>sonatype-nexus-snapshots</id>
		<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
	</repository>
</repositories>

DBUnitRule

This is a thin layer which drives DBUnit through a JUnit rule and some annotations.

Other projects exist which provide the same kind of functionality:

This DBUnit integration tries to keep things simple and not tied to any other framework.

DBUnitRule only needs 2 things to work:

  • A ResourceLoader to resolve (xml) data-sets
  • A ConnectionProvider to provide the database connection(s) to work on

NEW: A static factory method DBUnitRule.defaultSettings(Object testInstance) gives you a DBUnitRule configured with:

  • A ResourceLoader which will load resource on the classpath relative to the test class
  • A ReflectionConnectionProvider which will scan your test instance for public fields or methods returning IDatabaseConnection, Connection or DataSource and annotated with @DBUnitDataSource.

Simple example

@Rule
public final DBUnitRule dbUnit = new DBUnitRule(
    ResourceLoader.fromClass(this),
    name -> new DatabaseConnection(DriverManager.getConnection("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1", "sa", ""))
);
    
@Test
@DBUnit(dataSets = "initial.xml", expectedDataSets = "expected.xml")
public void testSomething() { ... }    

ResourceLoader

The ResourceLoader is given to the DBUnitRule so that it can load the data-set.

public interface ResourceLoader {
	
    InputStream loadResource(String name) throws IOException;
}   

Various static methods provide ready-to-use implementations (for classpath, files...)

ConnectionProvider

The ConnectionProvider must also be given to the DBUnitRule and provides (named) database connections.

public interface ConnectionProvider {

    IDatabaseConnection getConnection(String name) throws Exception;
}

Notice that the return type is DBUnit IDatabaseConnection.

If your test only uses one connection, you can provide a ConnectionProvider like this:

ConnectionProvider cp = name -> new DatabaseConnection(DriverManager.getConnection("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1", "sa", ""));

If you have a DataSource:

DataSource dataSource = ...;
ConnectionProvider cp = name -> new DatabaseDataSourceConnection(dataSource);

If you are using JNDI with multiple DataSources:

ConnectionProvider cp = name -> new DatabaseDataSourceConnection(new InitialContext(), "java:comp/env/jdbc/" + name));

When using multiple DataSource, you can specify the connection name via the @DBUnit annotation:

@Test
@DBUnit(name = "customerDB" dataSets = "initial-customers.xml", expectedDataSets = "expected-customers.xml")
@DBUnit(name = "orderDB" dataSets = "initial-orders.xml", expectedDataSets = "expected-orders.xml")
public void testSomething() { ... }

There is a new ReflectionConnectionProvider which will scan your test instance for public fields or methods returning IDatabaseConnection, Connection or DataSource and annotated with @DBUnitDataSource.

@DBUnitDataSource("customName")
private DataSource dataSource;

...

ConnectionProvider cp = name -> new ReflectionConnectionProvider(this); // this = test instance

Mixing DBUnitRule with embedded containers like OpenEJB

If you are using an embedded container inside your integration tests, you can let that container manage the lifecycle of the DataSource and write just enough code to fetch the DataSource from the container to give it to the DBUnitRule:

@Properties({
	@Property(key = "defaultDataSource", value = "new://Resource?type=DataSource"),
	@Property(key = "defaultDataSource.JdbcUrl", value = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"),
	@Property(key = "defaultDataSource.JdbcDriver", value = "org.h2.Driver"),
})
public class MyDatabaseIT {

    @ClassRule
    public static final EJBContainerRule CONTAINER = new EJBContainerRule(); 
	
    @Rule
    public final TestRule ruleChain = RuleChain
        .outerRule(new DBUnitRule(ResourceLoader.fromClass(this), name -> new DatabaseDataSourceConnection(CONTAINER.resource(DataSource.class, "defaultDataSource"))))
        .around(new InjectRule(this, CONTAINER))
        .around(new TransactionRule()); // transaction must come after dbunit
        
    @Test
    @DBUnit(dataSets = "initial.xml", expectedDataSets = "expected.xml")
    @Transaction
    public void testSomething() { ... }  
}

Alternatively, you could just @Inject the DataSource and use it in the @DBUnitRule (but make sure the injection rule is called before the dbunit one):

@Properties({
	@Property(key = "defaultDataSource", value = "new://Resource?type=DataSource"),
	@Property(key = "defaultDataSource.JdbcUrl", value = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"),
	@Property(key = "defaultDataSource.JdbcDriver", value = "org.h2.Driver"),
})
public class MyDatabaseIT {

    @ClassRule
    public static final EJBContainerRule CONTAINER = new EJBContainerRule(); 

    @Inject
    private DataSource dataSource;
	
    @Rule
    public final TestRule ruleChain = RuleChain
        .outerRule(new InjectRule(this, CONTAINER)) // injection must come before dbunit
        .around(new DBUnitRule(ResourceLoader.fromClass(this), name -> new DatabaseDataSourceConnection(this.dataSource))
        .around(new TransactionRule()); // transaction must come after dbunit
        
    @Test
    @DBUnit(dataSets = "initial.xml", expectedDataSets = "expected.xml")
    @Transaction
    public void testSomething() { ... }  
}

If you are using some kind of transaction rule, make sure that it comes after the DBUnit rule (otherwise, changes made inside the test won't be visible by the DBUnitRule and you will get an assertion error).

If you are using OpenEJB ApplicationComposer:

@Resource
private DataSource dataSource;
	
@Rule
public final TestRule ruleChain = RuleChain
    .outerRule(new ApplicationComposerRule(this)) // injection must come before dbunit
    .around(new DBUnitRule(ResourceLoader.fromClass(this), name -> new DatabaseDataSourceConnection(this.dataSource)));
	
@Configuration
public Properties configuration() {
    Properties configuration = new Properties();
    configuration.setProperty("defaultDataSource", "new://Resource?type=DataSource");
    configuration.setProperty("defaultDataSource.JdbcUrl", "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1");
    configuration.setProperty("defaultDataSource.JdbcDriver", "org.h2.Driver");
    return configuration;
}

@Module
public Any applicationComposerModule() { ... }

@Test
@DBUnit(dataSets = "initial.xml", expectedDataSets = "expected.xml")
public void testSomething() { ... } 

TODO Arquillian

EntityManagerRule

TODO

org.codegeny

Codegeny

Versions

Version
0.0.2