This project has moved to be a sub-project of Framework Libraries and is located here
Pull requests against this project have been disabled. Please contact one of the project owners for emergency bug fixes on this version
A domain-specific language (DSL) for testing aggregate roots and events using domain language:
- Given/When/Then based
- Feature files contain scenarios in plain language that business people can understand
- The Domain Test DSL library automatically tests the Java code implementing aggregate roots according to the behaviour described in the feature files
The implementation of our business domain is event sourced, so we can describe the current state (the Given clause) as a list of events that have already happened. When we perform an action on our domain model (the When clause), the result (the Then clause) will always be a list of events that have now occurred as a consequence:
Scenario: Add ingredients to a recipe
Given recipe added
When you addIngredients to a Recipe from an ingredients list
Then ingredients added
The language heavily relies on the simple pattern implemented by the Aggregate interface in framework. Every interaction with an aggregate root follows the same pattern:
- Events that have occurred previously are applied to the aggregate root
- An action is performed on the aggregate root by calling one of its methods with some arguments
- Zero or more events are consequently emitted by the aggregate root
Since the Given and Then clauses are simply lists of event descriptions, the only complex part of this is the When clause. In order to interpret this, we need it to follow a fixed grammatical structure:
When you <do something> to an <aggregate root> using <some new information>
- <do something> is the action being performed, and has to be the method being called on the aggregate root
- <aggregate root> is the name of the Java class implementing the aggregate root
- <some new information> is optional, but if present is the data used to perform the action; the arguments passed to the method being called
- The joining words that can be used are specified by the Domain Test DSL library, but offer a flexible set of choices designed to allow phrases to read as close to well-written English as possible
In terms of the code implementation, events and input data are provided as JSON files. The example scenario above translates to the following steps when running the test:
- Create a new instance of the aggregate root class
Recipe
. - Load some data for a
RecipeAdded
event from a JSON file calledrecipe-added.json
- Apply the
RecipeAdded
event to theRecipe
aggregate root - Load some data for the action from a JSON file called
ingredients-list.json
- Call the
addIngredients
method on theRecipe
using the action data - Collect the events emitted from the action method
- Assert that the collected events match the event data in a file called
ingredients-added.json
recipe-added.json
{
"_metadata": {
"name": "recipe-added"
},
"recipeId": "5c5a1d30-0414-11e7-93ae-92361f002671",
"name": "Cheese Cake",
"glutenFree": true
}
ingredients-list.json
{
"ingredients": [{
"name": "sugar",
"quantity": 500
}, {
"name": "custard",
"quantity": 2
}
]
}
ingredients-added.json
{
"_metadata": {
"name": "ingredients-added"
},
"recipeId": "5c5a1d30-0414-11e7-93ae-92361f002671",
"ingredients": [{
"name": "sugar",
"quantity": 500
}, {
"name": "custard",
"quantity": 2
}
]
}