java-testsupport
A collection of unit testing utilities.
JMock Extensions
An extension to JMock, supporting autowiring of mocks, was originally developed here, but has now moved into Apache Isis (in the org.apache.isis.core:isis-core-unittestsupport
module).
See this blog post for the original discussion on the features; see the Isis documentation for the current documentation.
Code Coverage
The objective of these utilities is to take some of the automate the testing of 'trivial' code which would otherwise be tedious to test. The point is not so much that we expect the tests to fail, but to be able to increase the code coverage figures. Thus, any figure less than 100% represents real business logic that has not been tested.
You could also think of these tests as contract tests, enforcing the (usually implied) contract of what it means for a class to be a pojo, or a Util
class, or a value type.
PojoTester
Exercises getters and setters of a pojo, this utility exercises them automatically. All primitive, strings, dates and java.math values are automatically exercised. The FixtureDatumFactory
interface allows representative instances of other types to be provided.
For example, the following exercises the AgreementRole
class (which in addition to the built-ins has a properties of type Agreement
, Party
and AgreementRoleType
):
@Mock
protected DomainObjectContainer mockContainer;
@Test
public void test() {
PojoTester.relaxed()
.withFixture(dates())
.withFixture(DomainObjectContainer.class, mockContainer)
.withFixture(FixtureDatumFactoriesForAnyPojo.pojos(
AgreementRoleType.class))
.withFixture(FixtureDatumFactoriesForAnyPojo.pojos(
Agreement.class, AgreementForTesting.class))
.withFixture(FixtureDatumFactoriesForAnyPojo.pojos(
Party.class, PartyForTesting.class))
.exercise(new AgreementRole());
}
private static FixtureDatumFactory<LocalDate> dates() {
return new FixtureDatumFactory<LocalDate>(LocalDate.class, new LocalDate(2012, 7, 19), new LocalDate(2012, 7, 20), new LocalDate(2012, 8, 19), new LocalDate(2013, 7, 19));
}
PrivateConstructorTester
This utility simply instantiates any classes (such as Util
classes) that have a private constructor.
For example:
@Test
public void invokeConstructor() throws Exception {
new PrivateConstructorTester(Constants.class).exercise();
}
where:
public static class Constants {
private Constants() {
// this is where we want some coverage!
}
public final static int FOO = 1;
public final static int BAR = 1;
}
ValueTypeContractTestAbstract
A utility to check the contract for value types was originally developed here, but has now moved into Apache Isis (in the org.apache.isis.core:isis-core-unittestsupport
module).
See this blog post for the original discussion on the features; see the Isis documentation for the current documentation. (As of isis-core-1.3.0-SNAPSHOT and later, this utility also tests value types that are Comparable
).
DBUnitRule
The DbUnitRule
bootstraps an instance of HsqlDB for each test and uses DbUnit to load data and assert on changes, using JSON to hold the datasets. See this blog post for further discussion.
DBUnit is licensed under LGPL 2.1, which is incompatible with a pure Apache License v2.0 library. For this reason the dbunit dependency is marked as <optional>true</optional>. If you wish to use this feature, make sure you include the dbUnit dependency directly.
The following example shows a possible use:
public class DbUnitRuleTest {
@Rule
public DbUnitRule dbUnit =
new DbUnitRule(DbUnitRuleTest.class, jdbcDriver.class,
"jdbc:hsqldb:file:src/test/resources/testdb",
"SA", "");
@Ddl("customer.ddl")
@JsonData("customer.json")
@Test
public void update_lastName_verifyUsingDataSets() throws Exception {
// when
Statement statement = dbUnit.getConnection().createStatement();
statement.executeUpdate(
"update customer set last_name='Bloggs' where id=2");
// then
ITable actualTable =
dbUnit.createQueryTable("customer",
"select * from customer order by id");
ITable expectedTable =
dbUnit.jsonDataSet("customer-updated.json").getTable("customer");
Assertion.assertEquals(expectedTable, actualTable);
}
}
where customer.ddl
is:
drop table customer if exists;
create table customer (
id int not null primary key
,first_name varchar(30) not null
,initial varchar(1) null
,last_name varchar(30) not null
)
and customer.json
is:
{
"customer": [
{
"id": 1, "first_name": "John", "initial": "K", "last_name": "Smith"
},
{
"id": 2, "first_name": "Mary", "last_name": "Jones"
}
]
}
and customer-updated.json
is:
{
"customer": [
{
"id": 1, "first_name": "John", "initial": "K", "last_name": "Smith"
}, {
"id": 2, "first_name": "Mary", "last_name": "Bloggs"
}
]
}
Hamcrest Matchers
The library provides a Hamcrest matcher to assert on the contents of object graphs. This idea was originally discussed in this blog post
For example:
@Test
public void customer_address_city_name() throws Exception {
assertThat("London", navigatedFrom(customer, "address.city.name"));
}
The matcher also supports collections. Behind the scenes it uses the MVEL expression language.
Legal Stuff
License
Copyright 2013 Dan Haywood
Licensed under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
Dependencies
<dependencies>
<dependency>
<!-- Common Public License - v 1.0 -->
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
<dependency>
<!-- ASL v2.0 -->
<groupId>org.mvel</groupId>
<artifactId>mvel2</artifactId>
<version>2.1.6.Final</version>
</dependency>
<dependency>
<!-- GNU Lesser General Public License, Version 2.1 -->
<groupId>org.dbunit</groupId>
<artifactId>dbunit</artifactId>
<version>2.4.9</version>
<!--
marked as optional due to the license; include explicitly
-->
<optional>true</optional>
</dependency>
<dependency>
<!-- ASL v2.0 -->
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>14.0.1</version>
</dependency>
<dependency>
<!-- ASL v2.0 -->
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>1.9.12</version>
</dependency>
<dependency>
<!-- ASL v2.0 -->
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.12</version>
</dependency>
<dependency>
<!-- ASL v2.0 -->
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<!-- ASL v2.0 -->
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.5</version>
</dependency>
</dependencies>