jixture

Easy fixture loading in Java

“fixture”?

A test fixture is something used to consistently test some item, device, or piece of software.

For instance by loading a database with a predefined set of data.

Why jixture?

To provide easy database fixture loading in a Spring/Hibernate environment.

How easy?

  • Supports database transactions out of the box
  • Basic (but sufficient) support for foreign-key constraints
  • Supports several fixture sources for a given test
  • Can handle various source formats
  • Support extraction of loaded fixtures

Which formats?

The following fixture formats are implemented:

  • Java code
  • XML files (DBUnit compatible)
  • Excel sheets
  • SQL scripts
  • Spring beans
  • Generated by code

And it's easy to implement your own if needed!

Ready for some action?

We need some dependency


<dependency>
  <groupId>net.cpollet.jixture</groupId>
  <artifactId>jixture-hibernate3</artifactId>
  <version>1.0.0.rc3</version>
</dependency>
					

And some Spring wiring


<!-- you have to define a transactionManager bean somewhere -->
<alias name="transactionManager" alias="jixture.core.transactionManager"/>

<!-- bring the magic -->
<import resource="classpath:/spring/jixture-core-context.xml"/>
					

And now…

Let's write some tests

Test skeleton

						
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:/spring/test-context.xml"})
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
@Transactional
public class TestSomeClass {
}
						
					

Getting jixture to the mix

  • We want to load some fixture
  • Without committing data
						
@Autowired
@Qualifier("jixture.noCommitDatabaseTestSupport")
private DatabaseTestSupport databaseTestSupport;
						
					

Loading a fixture into database

						
@Before
public void setUp() {
  Data data = new Data();
  data.setId(1L);
  data.setValue("value");

  databaseTestSupport.addFixtures(new MappingFixture(data)).loadFixtures();
}
						
					

And you're all set!

But what if…

… I have a DBUnit file?

Pas de souci ™

Just use the XML file fixture

						
@Before
public void setUp() {
  databaseTestSupport.addFixtures(new XmlFileFixture("dbunit-data.xml")).loadFixtures();
}
						
					

And that's it

Ok but now I need the data to be committed

Easy!

Bring jixture.commitDatabaseTestSupport:

						
@Autowired
@Qualifier("jixture.commitDatabaseTestSupport")
private DatabaseTestSupport commitDatabaseTestSupport;

@Autowired
@Qualifier("jixture.noCommitDatabaseTestSupport")
private DatabaseTestSupport noCommitDatabaseTestSupport;
						
					

Et voilà

What about format XYZ you mentioned in the beginning?

Let's have a look

Excel sheets

Dependencies

							
<!-- For XLSX -->
<dependency>
  <groupId>org.apache.poi</groupId>
  <artifactId>poi-ooxml</artifactId>
  <version>3.9</version>
</dependency>

<!-- For XLS -->
<dependency>
  <groupId>org.apache.poi</groupId>
  <artifactId>poi</artifactId>
  <version>3.9</version>
</dependency>
							
						

Load fixture with

							
@Before
public void setUp() {
  databaseTestSupport
    .addFixtures(new XlsFileFixture("fixtures.xls"))   // loads XLS file
    .addFixtures(new XlsxFileFixture("fixtures.xlsx")) // loads XLSX file
    .loadFixtures();
}
							
						

Excel file format

  • One table per sheet
  • Sheet name corresponds to table name
  • Sheets having name beginning with “!” are ignored
  • First row value gives table's column name
  • Column name “!mode” is special
  • Possibility to use excel formulas

Column "!mode"?

  • tags the row as input or output row
  • if “in” or “all” the data will be inserted in database
  • with “out” or “all” the data will not be inserted but can be used in assertions

Example

SQL scripts

Load fixture with

Inline script

							
@Before
public void setUp() {
databaseTestSupport
  .addFixtures(new SqlFixture(new String[] {
    "insert into users ...", "insert into products ..."
  }, User.class, Product.class))
  .loadFixtures();
}
							
						

Load fixture with

External script

							
@Before
public void setUp() {
  databaseTestSupport
    .addFixtures(new SqlFileFixture("classpath:tests/fixtures/sql-fixture.sql",
      User.class, Product.class))
  .loadFixtures();
}
							
						

Spring beans

Load fixture with

							
@Before
public void setUp() {
  databaseTestSupport
    .addFixtures(new SpringFixture("classpath:tests/fixtures/spring-fixture.xml",
      User.class, Product.class))
    .loadFixtures();
}
							
						

Generated by code

The most complex fixture source…

…but the most powerful

Concepts

  • generate mappings using Java code
  • use mapping template
  • use generators to generate attributes values

When to use?

When you want to generate many different mapping that kind of look the same. For instance, orders that can be in one of the following statuses:

  • new
  • validated
  • in preparation
  • prepared
  • shipping
  • shipped

When to use

And submitted from different countries:

  • Switzerland
  • France
  • USA

Dependencies

							
<dependency>
  <groupId>commons-beanutils</groupId>
  <artifactId>commons-beanutils</artifactId>
  <version>1.9.2</version>
</dependency>
<dependency>
  <groupId>uk.com.robust-it</groupId>
  <artifactId>cloning</artifactId>
  <version>1.9.0</version>
</dependency>
							
						

Show me some code

							
@Before
public void setUp() {
  Order order = new Order();
  order.setOrderDate(new Date());

  GeneratedFixture generatedFixture = new GeneratedFixture();

  generatedFixture
    .addGenerators(GeneratedFixture
      .from(order)
      .addFieldGenerator("id", FieldGenerators.sequence(1))
      .addFieldGenerator("status", FieldGenerators.in(
        Status.NEW, Status.VALIDATED, Status.IN_PREPARATION, ...
      )
      .addFieldGenerator("country", FieldGenerator.in("Switzerland", "France", "USA")
      .addFieldGenerator("totalPrice", FieldGenerators.sequence(1, 5, 2))
    );

  databaseTestSupport.addFixtures(generatedFixture).loadFixtures();
}
							
						

Field generators

jixture support several field value generators:

  • DateSequence
  • {Integer,Long}Sequence
  • {Integer,Long,String}IndexSequence
  • SimpleStringGenerator
  • MultiFieldGenerator

Cleaning fixture

When to use?

When all you want to do is to (partially) clean the database

Code

							
@Before
public void setUp() {
  CleaningFixture fixture = new CleaningFixture(Product.class, Client.class, Order.class);
  databaseTestSupport.addFixtures(fixture).loadFixtures();
}
							
						

You mentioned “extraction of loaded fixtures”

What is this???

Well…

When loading fixture it may be convinient to get a subset of the inserted data

This is what an extractor does

Scope

Not all fixture sources can be used together with extraction.

The following can:

To make a long story short, all Fixture that implement ExtractionCapableFixture

Needed dependency

						
<dependency>
  <groupId>org.hamcrest</groupId>
  <artifactId>hamcrest-core</artifactId>
  <version>1.3</version>
</dependency>
						
					

Some code

						
fixture.addExtractorMatcher(ExtractorMatcher.create(new org.hamcrest.core.IsAnything()));
// extracor matcher can have a name

ExtractionResult extractionResult = fixture.getExtractionResult();

List entities = extractionResult.getEntities();
// or
// extractionResult.getEntities(Model.class);
// extractionResult.getEntities("extractor name");
// extractionResult.getEntities("extractor name", Model.class);
						
					

Resources

Questions?