Full developer guide
1. Fixtures Conventions
Introduction
Even though one of the objectives of
is to create a common language between the business experts and the development team, there will always be a certain degree of difference between the natural language and the programing language.
Hence comes the reason for having fixtures. Fixtures are the glue between the business expert examples and the software being developed.
When running the table,
uses a fixture to mediate between the example expressed in the table and the system under test.
Collaboration demands compromise
The goal of the fixture, is to translate from one language to the other so neither has to compromise their clarity or their design to match the other. The fixture is the compromise.
A fixture is any class. It does not have to extend or implement any base class/interface.
The fixture name
The fixture name is found right next to the interpreter specification.
| rule for |
FixtureName |
| .. |
.. |
|
| list of |
FixtureName |
| .. |
.. |
|
| do with |
FixtureName |
| .. |
.. |
|
Since a fixture is a Java or C# class, when GreenPepper execute the example, it will try to match the fixture name with a class name.
What about packages and namespaces?
Usually, Java classes are found inside package and C# inside namespaces.
| rule for |
com.xyz.stuff.FixtureName |
| .. |
.. |
Readability
The problem with packages and namespace and with the classes naming convention, camel casing and no spaces, is that they makes the example less readable for the business expert.
To help readability, we have the following options
Import tables
Import tables are special tables at the beginning of the document.
By using an import table we can remove the package from the fixture name thus improving the readability of the example.
In C#, the namespaces are also provided in the Import table.
| import |
| Sample.Application.Stuff |
When GreenPepper will search for fixtures in the code, it will look into all the packages/namespaces specified in the import tables.
| list of |
FixtureName |
| ... |
... |
GreenPepper will match com.xyz.stuff.FixtureName.
You can have more than one package or namespace imported in a document. Just add more lines to the import table.
| import |
| com.xyz.stuff |
| com.xyz.otherstuff |
| com.xyz.yapackage |
GreenPepper will search for the fixture in each of these packages until it finds a matching class.
Humanized name
Event without the package, programmatic naming conventions are not the most readable form for the name of the example.
This can be arranged by following the camel casing
conventions.
Use a free form with space separating each words for the fixture name. And makes the fixture class use camel casing.
GreenPepper will match the words of the fixture name with the camel cased class name.
|
fixture name
the fixture
a fixture with a very long name becomes |
TheFixture
AFixtureWithAVeryLongName |
 | When using the humanized version of fixture naming, you must use Import tables.
explicit package won't work ex: |list of | com.xyz.stuff.the fixture name| |
The fixture suffix
If you wish to clearly distinguish between your domain classes and the classes that serve as fixture, you can add the suffix Fixture at the end of the fixtures classes name.
When writing the example, you can omit the suffix Fixture from the fixture name. This keeps the example closer to the real domain.
| rule for |
bank account fixture |
| ... |
... |
and
| rule for |
bank account |
| ... |
... |
will both match
public class BankAccountFixture {
...
}
Constructor
A fixture can receive parameters during it's construction. You must have a public constructor that matches the numbers of parameters.
When no parameters are specified in the example, the fixture class must have a public constructor without parameters.
| rule for |
bank account |
| ... |
... |
public class BankAccountFixture {
public BankAccountFixture()
{ ... }
}
| rule for |
poker table |
ante |
5$ |
max bet |
100$ |
| ... |
... |
public class PokerTableFixture {
public PokerTableFixture(Ammount ante, Ammount maxBet)
{ ... }
}
2. Rule Validation (Rule For)
Definition
Specific Keywords for expected values
offers a list of useful keywords to support the Business Expert.
| Empty cells |
When a test cell is left blank, only shows the returned value |
| error |
When you expect an error, specify it in the cell to test that particular behavior |
Coloring
will visually show the test result by coloring each testing cell:
When the expected value match the returned value, the RuleForInterpreter colors the cell as "right" by coloring it green.
If the values don't match, the RuleForInterpreter colors the cell as "wrong" in red.
If the system encounters an execution error, the cell is colored yellow and
provides information about the error.
If no expected value is specified in a test, the RuleForInterpreter colors the cell in gray.
Here is an example of cell coloring:
| rule for |
calculator |
| x |
y |
sum? |
product() |
quotient? |
| 10 |
0 |
10 |
0 |
0 |
| 6 |
3 |
9 |
-5 |
|
Writing fixtures for Rule Tables
As we've seen in Rule For definition, a table of rules is used to express business rules of the application under development.
A fixture for a table of rules defines how the specific given and expected columns of a rule table are mapped to the system under development.
This page shows the fixture code that supports the examples introduced in the Writing a Rule For specification documentation.
Fixture for Calculator
Consider the first example of business rule table described in Table of Rules documentation, shown again below.
| rule for |
Division |
| dividend |
divisor |
quotient? |
| 6.0 |
2.0 |
3.0 |
| 7 |
2 |
3.5 |
| 18 |
3.0 |
6 |
| 15 |
2 |
7.5 |
The first cell of the first row indicates that a RuleForInterpreter will be used to interpret the example table. The next cell says that the fixture to use is called Calculator. In Java, the name of the fixture is the name of a Java class.
The second row, also know as the header row, designates the given columns and expected columns. In the example, dividend and divisor are given columns, whereas quotient? is an expected column.
The fixture code to support this example in Java is the class Calculator shown below.
Show me the code
public class Division
{
public double dividend;
public double divisor;
public double quotient()
{
return dividend / divisor;
}
}
That class follows the general rules of fixtures described in 1. Fixtures Conventions. It exposes the instance variable dividend to map with the given column dividend. The given column divisor corresponds to the public instance variable divisor. The expected column quotient? is mapped to the public instance method quotient().
 | Note
This is a very simple example in which the fixture object does not call on the system under development, but performs the calculation. The quotient() method uses the instance variables dividend and divisor to perform the calculation by itself. |
How is the table processed?
When it runs this table,
reads the first row to select the interpreter and fixture. It then reads the second to know what are the given and expected columns. Finally it starts testing from the third row down to the end of the table.
For the third row
carries out the following sequence of steps:
- It assigns the value 6.0 to the dividend instance variable
- It assigns the value 2.0 to the divisor instance variable
- It calls the method quotient() of the fixture to get the value calculated by the system under development.
- It reads the value 3.0 from the quotient? column and compares it to the value returned by the fixture. Since the values are equal, it will annotate the cell as right, which results in the cell being colored green.
Same goes for the fourth and fifth rows.
On the other hand, on the last row the comparison will fail.
will mark the expected cell wrong. That cell will be colored red and will display a message including the expected value and the actual value.
How are the types of the values handled?
The instance variables dividend and divisor are of type double, so the given values in the example table needs to be double as well. For the fourth row,
will automatically convert the given values 7 and 2 to doubles before assigning them to the instance variables.
The return value of the quotient method is also a double, which means that the values provided in the quotient? expected column must be doubles as well. When
compares the value returned by the fixture with the value provided as an expectation, it will first convert the expected value to the type of the actual returned value. In the fifth row, it will convert the value 6 to a double and then do the comparison.
A More Realistic Example
The Calculator example is very simple. In a real world example, the fixture code would not perform any real work but would instead delegate to the application under development. In other words, if this was a real application the fixture would not carry out the division operation but call on the system under development. The general rule is to keep the fixture as thin as possible to be merely a mediator between the example table and the application code.
The Mortgage example described in [Writing a Rule For specification ] document better illustrates the role of the fixture and its interactions with the system under development. This example is shown again here:
| rule for |
insurance premium fee calculation |
| sale price |
down payment |
premium fee? |
financed amount? |
| $100,000 |
$15,000 |
$2,125.00 |
|
| $100,000 |
$30,000 |
$0.00 |
|
| $100,000 |
$25,000 |
$0.00 |
|
This example uses the InsurancePremiumFeeCalculation fixture class. The two given columns, which are sale price and down payment, are mapped respectively to the instance variables salePrice and downPayment. The two expected columns, called premium fee? and financed amount?, correspond respectively to the methods premiumFee() and financedAmount().
How are spaces between words handled?
You have noticed that you can separate words in the example table with spaces.
will convert the sequence a space-separated words to a valid Java identifier by removing the spaces and capitalizing the first letter of every word except the first one. This is called camel casing.
- For class names,
uses upper camel casing with the first letter of the identifier capitalized as well. In our example, the label insurance premium fee calculation is converted to the class name InsurancePremiumFeeCalculation.
- For method or instance variable names,
uses lower camel casing where the first letter of the identifier is left in lowercase.
Show me the code
The supporting code is here:
public class InsurancePremiumFeeCalculationFixture
{
public Money salePrice;
public Money downPayment;
public Money premiumFee()
{
InsuranceFee insuranceFee = new InsuranceFee(salePrice);
return insuranceFee.forDownpayment(downPayment);
}
public Money financedAmount()
{
return salePrice.minus(downPayment);
}
}
In this example, the fixture merely delegates the work to the application under development. Namely, the InsuranceFee domain object is responsible for performing the actual work.
The code for the system under development is:
public class InsuranceFee
{
private final Money salePrice;
public InsuranceFee(Money salePrice)
{
this.salePrice = salePrice;
}
public Money forDownpayment(Money downPayment)
{
return downPayment.greaterThan(salePrice.times(Ratio.percent(25))) ? Money.zero() : financedAmount( downPayment ).times( Ratio.of(25, 1000) );
}
private Money financedAmount(Money downPayment)
{
return salePrice.minus( downPayment );
}
}
What about the empty column?
The financed amount? expected value is left empty to tell
that this is an information column. We don't want to perform any test in that column, but rather show the value to help our understanding of the calculation. The calculated values will be shown when the example is run and marked with the ignored annotation, making them appear gray.
How are application value types handled?
We've seen that
will automatically convert the given values in the table to the type of the corresponding instance variable.
This is done automatically for the most common built-in Java types. The mortgage example, however, uses a money type, which is defined by the application under development in the Money business domain class.
When
encounters a custom type while performing conversion, it will look for a public static method called parse to handle the conversion from a String to the custom type. To do the conversion from the custom type to a String, it will call the method toString() on the custom type.
When
verifies an expected value to an actual value for a custom type, it does the following steps. It:
- Converts the expected value specified as a string in the table to the custom type using the parse(String text) method.
- Compares the expected value and the actual value using the equals(Object other) method on the expected value, passing it the actual value.
Here's the relevant part of the code for the Money class:
public class Money
{
private final BigDecimal dollars;
public Money(BigDecimal dollars)
{
this.dollars = dollars;
}
public static Money parse(String text)
{
return new Money( new BigDecimal( normalize( text ) ) );
}
private static String normalize(String text)
{
return text.replaceAll( "\\$", "").replaceAll( ",", "").replaceAll( "\\s", "");
}
public boolean equals(Object other)
{
if (other instanceof Money)
{
Money that = (Money) other;
return this.dollars.compareTo( that.dollars ) == 0;
}
else
{
return false;
}
}
public int hashCode()
{
return dollars.hashCode();
}
public String toString()
{
return "$" + dollars;
}
}
(new in 2.9) Row actions in ruleFor
There are 3 annotations(attributes) that can be used in the fixture with a RuleForInterpreter.
- BeforeRow
- AfterRow
- BeforeFirstExpectation
BeforeRow
A method annotated with BeforeRow will be call at the beginning of each new row so you can prepare your fixture.
AfterRow
A method annotated with AfterRow will be call at the end of each row so you can reset your fixture.
BeforeFirstExpectation
The method annotated with BeforeFirstExpectation will be call on each row just before the first ExpectedColumn(column with a ?) is encounter so you can prepared the return values for this row.
public class DomainStuffFixture
{
private DomainStuff stuff;
private int x;
private int y;
public void setX(int x)
{
this.x = x;
}
public void setY()
{
this.y = y;
}
@BeforeFirstExpectation
public void allocateDomainStuff() {
stuff = DomainStuffService.allocateDomainStuff(x, y);
}
public int getComputedValueOne()
{
return stuff.getComputedValueOne();
}
public int getOtherComputedValueO()
{
return stuff.getOtherComputedValue();
}
@AfterRow
public void freeDomainStuff() {
DomainStuffService.freeStuff(stuff);
}
}
The three annotations are optionals, you can use none, some or all of them in your fixture dependiong on your needs.
Let's Wrap Up
When
runs a rule table example, it creates a fixture class from the name indicated in the second cell of the first row. That class is used to mediate between the development table and the application code when checking the example against the system under development.
The second row of the table is the header row and is read from left to right. Two types of columns are supported in rule tables:
- given values, which are mapped to public instance variables in the fixture class
- expected values, which are checked against values returned by the corresponding public instance methods
For a given column header cell,
:
- Figures out the public instance variable to use using camel casing rules.
- If there is no instance variable that matches the label of the column header, it marks the cell with an error annotation, causing the cell to appear yellow and to display a stack trace of the error. That column will be ignored entirely.
For an expected column header cell:
- It figures out the public instance method to use using camel casing rules.
- If there is no such method or if it's not publicly accessible, it marks the cell with an error annotation, causing the cell to appear yellow and to display a stack trace of the error. That column will be ignored entirely.
Columns
will then run all remaining rows one at a time, going through all cells in the row from left to right.
For a given column:
- It converts the text entered in the cell to the type of the instance variable. To do that it uses either built-in converters (for basic Java types) or delegates to a method called parse (for domain types).
- It assigns the converted value to the instance variable.
- However, if type conversion fails, the cell is reported as an error.
For an expected column:
- It converts the text entered in the cell to the return type of the instance method. To do that it uses either built-in converters (for basic Java types) or delegates to a method called parse (for domain types).
- It compares the actual value to the converted value based on the definition of the equality for the type.
- If the values match, it marks the cell with a right annotation causing it to appear green.
- If the values do not match, it marks the cell with a wrong annotation so that it appears red and displays the expected and actual values.
- However, if type conversion fails or if the method throws an exception the cell is reported as an error.
3. List Validation (List of, Set of, Superset of, Subset of)
Definition
The collection interpreters are used to express any kind of groups, lists or sets of values.
When a collection interpreter is executed,
compares the list of values expected with the list of values returned by the system under development. The test result depends on the specific collection interpreter selected.

- As for all other interpreters, the first row of the collection interpreters specifies the name of the interpreter and the name of the collection to be tested.
- The next row is used to define the name of each attribute related to the members of the collection of data.
- The following rows are used to specify the set of values to test.
Specific keywords
None
Colouring
will visually indicate the test result by colouring the rows:
As expected, the row is returned by the system under development.
A row is missing or in surplus in the list returned by the system under development.
If the system encounters an execution error, the cell is in yellow, and
provides information about the error.
Particular behaviour for the list of interpreters:
Since the ListOfInterpreter expects to match exactly the expected list and the list returned by the SUD,
compares each cell of the table separately. If the expected value is different from the returned value,
colours the cell in red and provide the two values.
Particular behaviour for the superset of interpreters:
Since the SupersetOfInterpreter accepts that the specification may contain rows that are not contained in the SUD,
will not colour the rows contained in the specification but not returned by the SUD.
Writing fixtures for List tables
Writing fixtures for List of Value
As we've seen in the Collection Interpreters definition, the collection interpreters are used to express a collection of data to be compared with the system under development.
When running the table,
uses a fixture to mediate between the example expressed in collection of values tables and the system under development. The fixture code defines how the specific lists of values are mapped to the application code.
This page shows the fixture code that supports the examples introduced in the
| Import |
| com.greenpepper.samples.application.phonebook |
Using the CollectionInterpreter alone
Consider the example of collection of values table described in Collection Interpreters definition, shown again below.
| list of |
Canada Province Codes |
| Name |
Code |
| ALBERTA |
AB |
| BRITISH COLUMBIA |
BC |
| MANITOBA |
MB |
| NEW BRUNSWICK |
NB |
| NEWFOUNDLAND and LABRADOR |
NL |
| NOVA SCOTIA |
NS |
| NUNAVUT |
NU |
| ONTARIO |
ON |
| PRINCE EDWARD ISLAND |
PE |
| QUEBEC |
QC |
| SASKATCHEWAN |
SK |
| YUKON |
YT |
| OTHER PROVINCE |
OP |
The first cell of the first row indicates that a the ListOfInterpreter will be used to interpret the example table. The next cell says that the query() method to use is in the fixture named Canada Province Codes. In Java, the name of the fixture is the name of a Java class. The returned value of the query() method must be a Collection which is, in our example, a Set of Provinces.
The second row, also known as the header row, designates the attribute columns of the Collection's elements. In our example, Name and Code are the attribute of the Province.
The fixture code to support this example in Java is the class CanadaProvinceCodesFixture shown below.
The query method
The GreenPepper method called to get the list of data from the fixture is query() in Java and Query() in C#.
public Collection query() {...}
or
public ICollection Query() {...}
The return type of the query method does not have to be specifically a Collection/ICollection.
It can be any of the derived Collection class or an Array.
public Employees[] query() {...}
or
public Set<Something> Query() {...}
You can choose another method then query by telling GreenPepper which method to use with the help of an annotation or attributes.
import com.greenpepper.reflect.CollectionProvider;
...
@CollectionProvider
public Collection query() {...}
or
using GreenPepper.Reflect;
...
[CollectionProvider]
public ICollection Query() {...}
but the method specifies still have to be parameterless and return a Collection/ICollection implementation or an array.
Show me the code
public class CanadaProvinceCodesFixture
{
public Set<Province> query()
{
return Country.canada().provinces();
}
}
public class Country
{
private String name;
private Set<Province> provinces = new TreeSet<Province>();
private Country(String name)
{
this.name = name;
}
public static Country canada()
{
Country canada = new Country("CANADA");
canada.provinces.add(new Province("ALBERTA","AB"));
canada.provinces.add(new Province("BRITISH COLUMBIA","BC"));
canada.provinces.add(new Province("MANITOBA","MB"));
canada.provinces.add(new Province("NEW BRUNSWICK","NB"));
canada.provinces.add(new Province("NEWFOUNDLAND and LABRADOR","NL"));
canada.provinces.add(new Province("NOVA SCOTIA","NS"));
canada.provinces.add(new Province("NUNAVUT","NU"));
canada.provinces.add(new Province("ONTARIO","ON"));
canada.provinces.add(new Province("PRINCE EDWARD ISLAND","PE"));
canada.provinces.add(new Province("QUEBEC","QC"));
canada.provinces.add(new Province("SASKATCHEWAN","SK"));
canada.provinces.add(new Province("YUKON ","YT"));
return canada;
}
public Set<Province> provinces()
{
return provinces;
}
}
public class Province implements Comparable
{
public String name;
public String code;
public Province(String name, String code)
{
this.name = name;
this.code = code;
}
public int compareTo(Object o)
{
return name.compareTo(((Province)o).name);
}
}
How is the table processed?
When it runs this table,
reads the first row to select the interpreter and fixture. It then reads the second to know what are the attribute columns. Finally it starts testing from the third row down to the end of the table.
For the third row
carries out the following sequence of steps:
- It calls the method query() of the fixture CanadaProvinceCodesFixture to retrieve the Collection to test.
- It reads the value ALBERTA from the column Name and compares it to the attribute Name of the first element of the List.
Since the values are equal, it will annotate the cell as right, which results in the cell being colored green.
- It reads the value AB from the column Code and compares it to the attribute Code of the first element of the List.
Since the values are equal, it will annotate the cell as right, which results in the cell being colored green.
Step 2 and 3 are repeated through the remaining rows of the table.
For the fourth row, the Codes are not the same so

will mark the expected cell wrong. The cell will be colored red and will display a message including the expected value and the actual value.
The order of Provinces NEW BRUNSWICK and MANITOBA are inverted compared to the alphabetical sorting.

will annotate both rows as
wrong. Each cell will be colored red and will display a message including the expected value and the actual value.
The last row is not part the set of Province returned by the system under development. In that particular case,
will insert the keyword missing and color the row in red.
Using a CollectionInterpreter joined with the DoWithInterpreter
In this particular case, there is only one fixture combining the methods of the CollectionInterpreter and the methods of the DoWithInterpreter. So, in the CollectionInterpreter table, the second cell of the first row says which method to call from the DoWithInterpreter fixture.
Consider the example of the Phone Book application as described in Collection Interpreters definition. The DoWithInterpreter will insert entries in the Phone Book. The ListOfInterpreter is then used to test that the Phone Book really contains the inserted entries.
1. We use the DoWithInterpreter to create our personal phone book.
| do with |
phone book |
| insert |
Fred |
|
Flintstone |
with number |
(123) 456-7890 |
| insert |
Barney |
|
Rubble |
with number |
(123) 321-7666 |
| insert |
Great |
|
Gazoo |
with number |
(123) 989-4455 |
2. The test to be performed is: The requirement list should be the same as the SUD list.
| list of |
Phone book entries |
| FirstName |
LastName |
| Fred |
Flintstone |
| Betty |
Rubble |
| Great |
Gazoo |
| Wilma |
Flintstone |
Show me the code
public class PhoneBookFixture
{
private PhoneBook phoneBook = new PhoneBook();
public void insertWithNumber(String firstName, String lastName, String number)
{
phoneBook.insert(new PhoneBookEntry(firstName, lastName, number));
}
public List<PhoneBookEntry> query()
{
return phoneBook.entries();
}
}
public class PhoneBook
{
private List<PhoneBookEntry> entries = new ArrayList<PhoneBookEntry>();
public void insert(PhoneBookEntry entry)
{
entries.add(entry);
}
public List<PhoneBookEntry> entries()
{
return entries;
}
}
public class PhoneBookEntry
{
public String firstName;
public String lastName;
public String number;
public PhoneBookEntry(String firstName, String lastName, String number)
{
this.firstName = firstName;
this.lastName = lastName;
this.number = number;
}
}
Writing fixtures for derived List of Value (SetOf, SubsetOf, SupersetOf)
The fixture writting and results annotations are exactly similar in all points.
Of course the behavior of the test will varry see Collection Interpreters definition for detail.
4. Workflow validation (Do With)
Definition
The DoWithInterpreter is used to express interactions with the system under development that must be performed in a particular order. This form of specification provides information about the business flow.
When a sequence of action is executed,
confirms that each action has successfully been performed.

- As for all other interpreters, the first row of the DoWithInterpreter specifies the name of the interpreter and the name of the sequence of actions to be tested. What makes the DoWithInterpreter particular is that it only have to be defined once for all the sequences of actions expressed in a page. Obviously, the DoWithInterpreter must be define before any sequence of actions.
- The following rows are used to express specific actions.
- The form of each row of a DoWithInterpreter shall respect the following rules:
- a row shall begin with a part of the action description,
- each parameter shall be isolated in a cell,
- each parameter shall be separated by parts of the action description.
- An action description can be left blank in order to separate two parameters.
- The DoWithInterpreter provide a minimum of keyword used to define specific action.
- The DoWithInterpreter may also be expressed in Bullet List form or Number List form.
Specific Keywords
offers a list of useful keywords to support the Business Expert. Those keywords are placed at the beginning of an action row.
| Accept |
Confirm that the action as been executed by the system under development. |
| Check |
Verify the specified expected value with the value returned by the system under development |
| Reject |
The action should not be performed by the system under development (expected errors). |
| Display |
Print the value returned by the system under development. |
Coloring
will visually show the test result by coloring each testing cell:
When the action has been executed successfully,
color the cell(s) in green.
If the action execution has failed,
color the cell(s) in red.
If the system encounters an execution error, the cell is colored yellow and
provides information about the error.
When the action has been executed successfully,
will display the returned value in gray.
| Standard form (without keyword) |
Only the Action description will be colored. |
| Accept |
Only the cell containing the keyword Accept will be colored. |
| Check |
The cell containning the expected value will be colored. In the case of a failure, will show the expected and the returned values. |
| Reject |
Only the cell containing the keyword Reject will be colored. |
| Display |
A new cell at the end of the row will be colored containing the returned value. |
Writing fixtures for Do With tables
As we've seen in the Do With definition, a sequence of tables is used to express a business flow in the application under development.
When running the table,
uses a fixture to mediate between the example expressed in the sequence of tables and the system under development. The fixture code defines how the specific actions are mapped to the application code.
This page shows the fixture code that supports the examples introduced in the Writing a Do With specification.
Fixture for Bank
Consider the first example of business flow described in Writing a Do With specification, shown again below.
| open checking account |
12345-67890 |
under the name of |
Spongebob |
|
Squarepants |
| check |
that balance of account |
12345-67890 |
is |
$0.00 |
The first table indicates to use a DoWithInterpreter, which handles a business flow expressed as a sequence of tables. The fixture Bank will do the mediation with the application under development.
The interpreter will run all the tables until the end of the document. In this case, the second and third tables compose the business flow example.
The second table indicates to perform the action open checking account under the name of on the system under development, with the parameters 12345-67890, Spongebob and Squarepants. That action will result in a call to the method openCheckingAccountUnderTheNameOf() on the fixture with the parameters 12345-67890, Spongebob and Squarepants.
The third table indicates to check the result of the action that balance of account is on the system under development with the expected value $0.00. That action results in a call to the method thatBalanceOfAccountIs on the fixture with the parameter 12345-67890. That method is expected to return a value, which will be asserted for equality against the domain representation for the value $0.00.
The fixture code to support this example in Java is the class BankFixture shown below.
Show me the code
public class BankFixture
{
private Bank bank;
public BankFixture()
{
bank = new Bank();
}
public boolean openCheckingAccountUnderTheNameOf(String number, String firstName, String lastName)
{
return bank.openCheckingAccount(number, new Owner(firstName, lastName)) != null;
}
public Money thatBalanceOfAccountIs(String accountNumber) throws Exception
{
BankAccount account = bank.getAccount(accountNumber);
return account.getBalance();
}
}
That class follows the general rules of fixtures described in 1. Fixtures Conventions. It provides public instance methods openCheckingAccount and thatBalanceOfAccount to map respectively to the actions open checking account and that balance of account.
 | Note
The fixture does not much except from delegating the processing to the application code, in this case the Bank class. |
public class Bank {
private final HashMap<String, BankAccount> accounts;
public Bank()
{
accounts = new HashMap<String, BankAccount>();
}
public boolean hasAccount(String accountNumber)
{
return accounts.containsKey(accountNumber);
}
public BankAccount getAccount(String accountNumber) throws NoSuchAccountException
{
if (!hasAccount(accountNumber)
throw new NoSuchAccountException(accountNumber);
return accounts.get(accountNumber);
}
public CheckingAccount openCheckingAccount(String number, Owner owner)
{
if (hasAccount(number)) return null;
CheckingAccount account = new CheckingAccount(number, owner);
accounts.put(number, account);
return account;
}
}
How is the example interpreted?
When it runs this example,
reads the first table to decide on the interpreter and fixture to use and start testing from the second table, which is the first test table.
The second table is a default action, which
carries out in the following sequence of steps:
- It calls the method openCheckingAccountUnderTheNameOf() with the parameters 12345-67890, Spongebob and Squarepants
- Since the method returns true, indicating a success, it marks the keyword cells as right, resulting in the first cell of the row being colored green.
The third table is a check action, which
carries out in the following sequence of steps:
- It calls the method thatBalanceOfAccountIs() with the parameter 12345-67890 to get the value calculated by the system under test
- This is a check action, so it reads the value $0.00 from the last cell of the row and compares it to the value returned by the fixture. Since the values are equal, it annotates the last cell as right, which results in the cell being colored green.
What happens for other return types?
Default Rows
Depending on the value returned by the system under test, default actions will annotate keyword cells following these rules:
- If the value is true, it annotates keyword cells right, making them appear green.
- If the value is false - indicating a failure - it annotates keywords cells wrong, making them appear red.
- If the action throws an exception, it annotates the first keyword as an exception, making it appear yellow and display a stack trace of the error.
- If the action returns another value or nothing, it ignores the result.
Check Rows
Depending on the value returned by the system under test, check actions will annotate the row following these rules:
- If the returned value matches the expected value, it annotates the last cell right, making it appear green.
- If the action returns nothing or a value that does not match the expected value - indicating a failure - it annotates the last cell wrong, making it appear red.
- If the action throws an exception, it annotates the first keyword as an exception, making it appear yellow and display a stack trace of the error.
Building on the Bank example
The second example in Writing a Do With specification, shown again below, presents a more complete business flow using the bank fixture.
| open checking account |
12345-67890 |
under the name of |
Spongebob |
|
Squarepants |
| check |
that balance of account |
12345-67890 |
is |
$0.00 |
| deposit |
$100.00 |
in account |
12345-67890 |
| check |
that balance of account |
12345-67890 |
is |
$100.00 |
| withdraw |
$50.00 |
from account |
12345-67890 |
| check |
that balance of account |
12345-67890 |
is |
$50.00 |
| reject |
withdraw |
$75.00 |
from account |
12345-67890 |
| check |
that balance of account |
12345-67890 |
is |
$50.00 |
| accept |
withdraw |
$25.00 |
from account |
12345-67890 |
The fourth and last example tables contain more several rows. In a sequence of actions, all of the rows in a table are executed, so several actions can be grouped in a table if that helps improve clarity.
In the first row of the last table, notice the use of the reject special keyword in the first cell. This indicates that the action for the row is expected to fail by either returning false or throwing an exception.
In the last row of the last table, the accept special keyword is used to indicate that we expect the last call to succeed. Accept is the opposite of reject. That is, the last withdraw should not return false nor throw an exception.
Reject Rows
Depending on the value returned by the system under test, reject actions will annotate the row following these rules:
- If the action returns false or throws an exception - indicating a success - it annotates the reject keyword right, making it appear green.
- If the returned value is anything else or nothing - indicating a failure - , it annotates the reject keyword wrong, making it appear red.
Accept Rows
Depending on the value returned by the system under test, accept actions will annotate the row following these rules:
- If the returned value is anything except false or an exception - indicating a success -, it annotates the accept keyword right, making it appear green.
- If the action returns false or throws an exception - indicating a failure - it annotates the accept keyword wrong, making it appear red.
Show me the code
The supporting code is here:
public class BankFixture
{
private Bank bank;
public BankFixture()
{
bank = new Bank();
}
public boolean openCheckingAccountUnderTheNameOf(String number, String firstName, String lastName)
{
return bank.openCheckingAccount(number, new Owner(firstName, lastName)) != null;
}
public Money thatBalanceOfAccountIs(String accountNumber) throws Exception
{
BankAccount account = bank.getAccount(accountNumber);
return account.getBalance();
}
public void depositInAccount(Money amount, String accountNumber) throws Exception
{
bank.deposit(amount, accountNumber);
}
public boolean withdrawFromAccount(Money amount, String accountNumber) throws Exception
{
return withdrawFromAccountUsing( amount, accountNumber, WithdrawType.ATM );
}
public boolean withdrawFromAccountUsing(Money amount, String accountNumber, WithdrawType withdrawType) throws Exception
{
try
{
bank.withdraw(amount, accountNumber, withdrawType);
}
catch (Exception e)
{
return false;
}
return true;
}
public Collection getOpenedAccounts()
{
return bank.getAccounts();
}
}
Combining with other types of rules
An interesting characteristic of the DoWithInterpreter is the ability to delegate processing of part of the table to another interpreter.
If an interpreter is specified in the first cell of a row, the remainder of the table will be processed by that interpreter. The action for the row must return a fixture that will be used to interpret the rest of the table.
In the example show below, the first row of the second table indicates to process the rest of the table using a SetOfInterpreter on the value returned by the action opened accounts.
| open checking account |
12345-67890 |
under the name of |
Spongebob |
|
Squarepants |
| open savings account |
54321-09876 |
under the name of |
Patrick |
|
Star |
| set of |
opened accounts |
| number |
type |
owner name |
| 12345-67890 |
checking |
Spongebob Squarepants |
| 54321-09876 |
savings |
Patrick Star |
Interpret Rows
Depending on the value returned by the system under test, interpret actions will annotate the row following these rules:
- If the returned value is an object, it uses the interpreter specified in the first cell on that object to interpret the remainder of the table. The row is not annotated.
- If the action returns nothing, it uses the interpreter without any fixture to interpret the remainder of the table. The row is not annotated.
- If the action throws an exception - indicating a failure - it annotates the first action keyword as exception, making appear yellow and display a stack trace of the error. The remainder of the table is not interpreted.
7. Scenario Fixture
Definition
The ScenarioInterpreter is used to express interactions with the system under development that must be performed in a particular order. This form of specification provides information about the business flow.
When a sequence of action is executed,
confirms that each action has successfully been performed.
| Scenario |
Identification of the set of rule |
| Action 1 |
| Action 2 |
| ... |
| Action i |
- As for all other interpreters, the first row of the ScenarioInterpreter specifies the name of the interpreter and the name of the sequence of actions to be tested. What makes the ScenarioInterpreter particular is that it only have to be defined once for all the sequences of actions expressed in a page. Obviously, the ScenarioInterpreter must be define before any sequence of actions.
- The ScenarioInterpreter may also be expressed in Bullet List form or Number List form.
Coloring
will visually show the test result by coloring a complete row or words inside the row:
When the action has been executed successfully,
color the row or words inside the row in green.
If the action execution has failed,
color the the row or words inside the row in red.
If the system encounters an execution error, the row is colored yellow and
provides information about the error.
When the action has been executed successfully,
will display the returned value in gray.
Writing fixtures for Scenario tables
As we've seen in the Scenario definition, a sequence of tables is used to express a business flow in the application under development.
When running the table,
uses a fixture to mediate between the example expressed in the sequence of tables and the system under development. The fixture code defines how the specific actions are mapped to the application code.
This page shows the fixture code that supports the examples introduced in the Writing a Scenario specification.
Fixture for Bank
Consider the first example of business flow described in Writing a Scenario specification, shown again below.
| open checking account 12345-67890 under the name of Spongebob Squarepants |
| verify that balance of account 12345-67890 is $0.00 |
The first table indicates to use a ScenarioInterpreter, which handles a business flow expressed as a sequence of tables. The fixture Bank will do the mediation with the application under development.
The interpreter will run all the tables until the end of the document. In this case, the second and third tables compose the business flow example.
The second table indicates to perform the action of opening a checking account 12345-67890 under the name of Spongebob Squarepants on the system under development. That action will result in a call to a method from the Bank fixture. The method will be found using Regular Expression assigned to an annotation.
Annotation & Regular Expression
To resolve the method to call, the ScenarioInterpreter will look at all fixture methods annotated with the following annotations and will try to match the action content to the regular expression on it. Parameters will be captured by the regular expression itself (using capture group).
 | Annotation with .Net
.Net annotation are in fact Attribute and are declared like [Given]. |
@Given
A Given annotation will be use when you need to put the system in a know state before a user interact with it. A good example will be to prepare the data in the system to be available for the next action calls. In our Bank example, this will represent the opening of the checking account action.
@When
A When annotation will be use for transiting the system to another state. A good example will be to interact with the system. In our Bank example this will represent deposit or withdraw actions.
@Then
A Then annotation will be use to verify the result of interactions on the system. A good example will be to check if an event has been raised. In our Bank example, this will represent the verification of the balance account.
@Check
A Check annotation will be use to verify the result of the action (boolean result equality). A good example will be to check if we can proceed with an action. In our Bank example, this will represent the verification whenever we can withdraw a certain amount.
@Display
A Display annotation will be use to show the result of the action (the actual result). The displayed value is only for information purpose. A good example will be to show an internal value. In our Bank example, this will represent showing the actual balance account.
If we continue with our example, the third table indicates to verify the balance account against the expected value $0.00. Here, we introduce a verification for an expected value and the actual value. This will be done using the Expectaction object as a parameter of the method to be call.
The fixture code to support this example in Java is the class BankFixture shown below.
Show me the code
public class BankFixture
{
private Bank bank;
public BankFixture()
{
bank = new Bank();
}
@Given("open (\\w+) account (\\d{5}\\-\\d{5}) under the name of ([\\w|\\s]*)")
public void openAccount(String type, String number, Owner owner)
{
if ("checking".equals( type ))
{
bank.openCheckingAccount( number, owner );
}
else if ("savings".equals( type ))
{
bank.openSavingsAccount( number, owner );
}
}
@Then("verify that balance of account (\\d{5}\\-\\d{5}) is (\\$\\d+\\.\\d\\d)")
public void theBalanceOfAccount(String number, Expectation expectedBalance) throws NoSuchAccountException
{
Money actualBalance = bank.getAccount( number ).getBalance();
expectedBalance.setActual( actualBalance );
}
}
That class follows the general rules of fixtures described in 1. Fixtures Conventions.
 | Note
The fixture does not much except from delegating the processing to the application code, in this case the Bank class. |
public class Bank {
private final HashMap<String, BankAccount> accounts;
public Bank()
{
accounts = new HashMap<String, BankAccount>();
}
public boolean hasAccount(String accountNumber)
{
return accounts.containsKey(accountNumber);
}
public BankAccount getAccount(String accountNumber) throws NoSuchAccountException
{
if (!hasAccount(accountNumber)
throw new NoSuchAccountException(accountNumber);
return accounts.get(accountNumber);
}
public CheckingAccount openCheckingAccount(String number, Owner owner)
{
if (hasAccount(number)) return null;
CheckingAccount account = new CheckingAccount(number, owner);
accounts.put(number, account);
return account;
}
}
How is the example interpreted?
When it runs this example,
reads the first table to decide on the interpreter and fixture to use and start testing from the second table, which is the first test table.
The second table is an action which
carries out in the following sequence of steps:
- Find a method that match the action content using regular expression defined on annotated method
- The parameter Owner will be instanciated by the type conversion facility and will contains Spongebob and Squarepants
- It calls the method openAccount() with the parameters 12345-67890 and the Owner object instance
- The behavior will be applied by the type of the annotation. In this case, it is a Given annotation and the row will not be colored green (except if an exception occur, the row will be colored red).
The third table is an action which
carries out in the following sequence of steps:
- Find a method that match the action content using regular expression defined on annotated method
- It calls the method theBalanceOfAccount() with the parameter 12345-67890 to get the value calculated by the system under test and the Expectation object instance
- This is a Then annotation. The method will set the actual value on the Expectation object instance. GreenPepper will then verify the Expectation object to see if it match the value $0.00. If the values are equal, it annotates the value $0.00 as right (green) or wrong (red) if not
Building on the Bank example
The second example in Writing a Scenario specification, shown again below, presents a more complete business flow using the bank fixture.
| open checking account 12345-67890 under the name of Spongebob Squarepants |
| verify that balance of account 12345-67890 is $0.00 |
| deposit $100.00 in account 12345-67890 |
| verify that balance of account 12345-67890 is $100.00 |
| withdraw $50.00 from account 12345-67890 |
| verify that balance of account 12345-67890 is $50.00 |
| can't withdraw $75.00 from account 12345-67890 |
| verify that balance of account 12345-67890 is $50.00 |
| can withdraw $25.00 from account 12345-67890 |
The fourth and last example tables contain more several rows. In a sequence of actions, all of the rows in a table are executed, so several actions can be grouped in a table if that helps improve clarity.
Show me the code
The supporting code is here:
public class BankFixture
{
private Bank bank;
public BankFixture()
{
bank = new Bank();
}
public BankFixture()
{
this.bank = new Bank();
}
@Given("open (\\w+) account (\\d{5}\\-\\d{5}) under the name of ([\\w|\\s]*)")
public void openAccount(String type, String number, Owner owner)
{
if ("checking".equals( type ))
{
bank.openCheckingAccount( number, owner );
}
else if ("savings".equals( type ))
{
bank.openSavingsAccount( number, owner );
}
}
@Then("verify that balance of account (\\d{5}\\-\\d{5}) is (\\$\\d+\\.\\d\\d)")
public void theBalanceOfAccount(String number, Expectation expectedBalance)
throws NoSuchAccountException
{
Money actualBalance = bank.getAccount( number ).getBalance();
expectedBalance.setActual( actualBalance );
}
@When("deposit (\\$\\d+\\.\\d\\d) in account (\\d{5}\\-\\d{5})")
public void deposit(Money amount, String number)
throws Exception
{
bank.deposit( amount, number );
}
@When("withdraw (\\$\\d+\\.\\d\\d) from account (\\d{5}\\-\\d{5})")
public void withdraw(Money amount, String number)
throws Exception
{
bank.withdraw( amount, number, WithdrawType.ATM );
}
@Check("can't withdraw (\\$\\d+\\.\\d\\d) from account (\\d{5}\\-\\d{5})")
public boolean cannotWithdraw(Money amount, String number)
{
try
{
bank.withdraw( amount, number, WithdrawType.ATM );
return false;
}
catch (Exception e)
{
return true;
}
}
@Check("can withdraw (\\$\\d+\\.\\d\\d) from account (\\d{5}\\-\\d{5})")
public boolean canWithdraw(Money amount, String number)
{
try
{
bank.withdraw( amount, number, WithdrawType.ATM );
return true;
}
catch (Exception e)
{
return false;
}
}
public Collection<BankAccount> getOpenedAccounts()
{
return bank.getAccounts();
}
}
Combining with other types of rules
An interesting characteristic of the ScenarioInterpreter is the ability to delegate processing of part of the table to another interpreter.
If an interpreter is specified in the first cell of a row, the remainder of the table will be processed by that interpreter. The action for the row must return a fixture that will be used to interpret the rest of the table.
In the example show below, the first row of the second table indicates to process the rest of the table using a SetOfInterpreter on the value returned by the action opened accounts.
| open checking account 12345-67890 under the name of Spongebob Squarepants |
| open savings account 54321-09876 under the name of Patrick Star |
| set of |
opened accounts |
| number |
type |
owner name |
| 12345-67890 |
checking |
Spongebob Squarepants |
| 54321-09876 |
savings |
Patrick Star |
Live example
See a live example here.
6. Context definition (Setup)
Definition
The SetUpInterpreter is used to simplify the creation of a particular state for the system under development. Once the state is created, we can focus on the business process to test.
When a setup table is executed,
enter data in the system under development to create the desired state.

- The first row of the table indicates the name of the interpreter and the name of the desired state.
- The second row is called the header row and serves to identify the data to be inserted in the system under development.
- Finally, the remaining rows captures the data to be inserted.
Coloring
will visually show the test result by coloring each testing cell:
When the insertion has been executed successfully,
add a green cell at the end of the data row with the word entered.
If the insertion has failed because the values specified does not respect a business rule,
add a red cell at the end of the row with the word not entered.
If the insertion has failed because a specified value generates an error,
colors the cell of the data in error yellow and provides information about the error.
If the system encounters an error not related to a specific data,
add a yellow cell at the end of the data row and provides information about the error.
Writing fixtures for Setup tables
As we've seen in Setup Definition, a table of rules is used to simplify the creation of a particular state for the system under development. Once the state is created, we can focus on the business process to test.
This page shows the fixture code that supports the examples introduced in the Writing a Setup specification.
Fixture to create bank customers
Consider the example of setup table described in Writing a Setup specification:
| Import |
| com.greenpepper.samples.application.bank |
| setup |
a group of customers |
| number |
type |
first name |
last name |
balance |
| 11111-11111 |
checking |
Fred |
Flintstone |
$250.00 |
| 22222-22222 |
savings |
Fred |
Flintstone |
$10 000.00 |
| 44444-44444 |
savings |
Wilma |
Flintstone |
$10 000.00 |
| 55555-55555 |
checking |
Barney |
Rubble |
$999.54 |
The first cell of the first row indicates that a the SetupInterpreter will be used to interpret the table. The next cell says that the enterRow() method to use is in the fixture named AGroupOfCustomers. In Java, the name of the fixture is the name of a Java class. The enterRow() will be used to enter the data.
Instead of writing a method enterRow(), you can annotate the setup method with the annotation @EnterRow for Java ([EnterRow] for .Net). This way you can have a meaningful name for the setup method.
The second row, also known as the header row, designates the attribute columns of the data to be inserted. In our example, number, type, first name, last name and balance are the information to be created in the system under development.
The fixture code to support this example in Java is the class AGroupOfCustomersFixture shown below.
Show me the code
public class AGroupOfCustomersFixture
{
public AccountType type;
public String number, firstName, lastName;
public Money balance;
public static Bank bank;
public AGroupOfCustomersFixture()
{
bank=new Bank();
}
@EnterRow
public void setupAccount()
{
if(AccountType.SAVINGS == type)
bank.openSavingsAccount(number, new Owner(firstName, lastName)).deposit(balance);
else if(AccountType.CHECKING == type)
bank.openCheckingAccount(number, new Owner(firstName, lastName)).deposit(balance);
}
}
How is the table processed?
When it runs this table,
reads the first row to select the interpreter and fixture. It then reads the second to know what are the attribute columns. Finally it starts creation of entries from the third row down to the end of the table.
For the third row
carries out the following sequence of steps:
It assigns the data 11111-11111 to number, checking to type, Fred to first name, Flintstone to last name and $250.00 to balance.
It then calls the method enterRow() of the fixture AGroupOfCustomersFixture to open a bank account with the given datas.
7. Advanced developer guide
Defining a custom system under development
Why ?
The system under development is a bridge between your Fixtures and the system your testing.
If you want to change the way
is finding/instanciating your fixtures, or if you need to hook the document execution then you can define a Custom System Under Development.
To change the system under development :
Using custom types
All the examples in the documents are in strings, but fixtures want to process and return other data types.
provides a mechanism to help conversion from String to other data types and back again.
| rule for |
SomeFixture |
with parameter |
100$ |
| color |
someBool |
answer |
| 255,55,10 |
yes |
14% |
| 235,5,0 |
no |
21% |
Will match a class with the following method
public class SomeFixture {
public SomeFixture(Ammount ammount) {...}
public setColor(RGB color) ...
public someBool(boolean yesNo)..
public Ratio answer()...
}
Lets look at how
will match these.
Converters
Converters are class implementing the interface com.greenpepper.converter.TypeConverter in java or GreenPepper.Converters.ITypeConverter in C#
public interface TypeConverter
{
boolean canConvertTo( Class type );
Object parse( String value, Class type );
String toString( Object value );
}
namespace GreenPepper.Converters
{
public interface ITypeConverter
{
bool CanConvertTo(Type type);
object ValueOf(string value, Type type);
string ToString(object value);
}
}
provides out of the box type converters for the following types
- Integer
- Long
- Float
- Double
- Date
- Boolean
- Array
- String
or their simpler form int, long ...
(order is important see adding a new type converter below)
The ArrayConverter calls recursively the other converters depending on the component type the array holds.
Adding a new type converter
The com.greenpepper.GreenPepper class provides a method to add your own type converter
public static void register( TypeConverter converter)
public static void Register( ITypeConverter converter)
The better place to register your custom type is in a custom system under developement :
public static class CustomSystemUnderDevelopment extends DefaultSystemUnderDevelopment
{
public CustomSystemUnderDevelopment( String... params )
{
GreenPepper.register(new MyCustomTypeConverter());
}
}
The converters are always check in an LIFO manners. If two converters can process a data type the last one that has been register will be used. That way, you can provides your own converters in place of the standard
converters.
Self conversion
Instead of registering a TypeConverter, you can uses self converting types.
Self converting type implies that you add a static parse method to your class.
Java
public static T parse(String val);
And then to revert back to a string,
public static String toString(T value)
C#
public static T ValueOf(string text)
And then to revert back to a string,
public static String ToString(T value)
Your class does not have to provides both of them.
Rules of conversion
From example to fixture
1 First
will verify if the type is can self convert (ie public static T parse(String) or public static T ValueOf(string))
2 If not, look for a registered TypeConverter that can handles the type.
3 An UnsupportedOperationException will be thrown
From fixture return value to String
1 First
will verify if the type is can self revert (ie public static String toString(T) or public static T ToString(string))
2 If not, look for a registered TypeConverter that can handles the type.
3 Use the toString() or ToString() method on the data itself.
Customizing GreenPepper fixture resolution
Prerequisite
To change fixtures resolutions you need to define a custom system under development
Changing how
is finding your Fixtures
This could be useful when you are using for example an IOC, like Spring or just when you want to add locations (packages in java, namespaces in .Net) for
can resolve your fixtures.
Only for specifying location to resolve fixtures (packages in java, namespaces in .Net)
public static class CustomSystemUnderDevelopment extends DefaultSystemUnderDevelopment
{
public CustomSystemUnderDevelopment( String... params )
{
super.addImport("com.mycompany.fixtures");
super.addImport("com.mycompany.specials.fixtures");
}
}
By this custom system under development you tell
to look in "com.mycompany.fixtures" and "com.mycompany.specials.fixtures" to resolve fixtures in specfications that your are running.
Changing Fixture instanciation mechanism (Spring example)
The Spring container system under development
Spring is an Inversion Of Control (IOC)
container get more information about it on Spring website
SpringSystemUnderDevelopment code can be found in greenpepper-extensions-spring: SpringSystemUnderDevelopment.java
package com.greenpepper.extensions.spring;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import com.greenpepper.reflect.DefaultFixture;
import com.greenpepper.reflect.Fixture;
import com.greenpepper.systemunderdevelopment.DefaultSystemUnderDevelopment;
public class SpringSystemUnderDevelopment extends DefaultSystemUnderDevelopment
{
private BeanFactory beanFactory;
public SpringSystemUnderDevelopment(String... applicationCtxes)
{
this.beanFactory = new GreenPepperXMLAplicationContext(applicationCtxes).getBeanFactory();
}
public SpringSystemUnderDevelopment(BeanFactory beanFactory)
{
this.beanFactory = beanFactory;
}
@Override
public Fixture getFixture(String fixtureName, String... params) throws Throwable
{
Fixture fixture;
if (params.length != 0)
{
fixture = super.getFixture(fixtureName, params);
}
else
{
try
{
fixture = new DefaultFixture(beanFactory.getBean(fixtureName));
}
catch (NoSuchBeanDefinitionException e)
{
fixture = new DefaultFixture(instantiateAsAutowiredBean(fixtureName));
}
}
return fixture;
}
private Object instantiateAsAutowiredBean(String fixtureName) throws Exception
{
Class fixtureClass = loadType(fixtureName).getUnderlyingClass();
BeanDefinition beanDef = new RootBeanDefinition(fixtureClass, RootBeanDefinition.AUTOWIRE_AUTODETECT);
DefaultListableBeanFactory fallFactory = new DefaultListableBeanFactory(beanFactory);
fallFactory.registerBeanDefinition(fixtureName, beanDef);
return fallFactory.getBean(fixtureName);
}
}
Hooking document execution
To hook a document execution, you need to define a custom sytem under development
Execute specifications with command line
Introduction
This page describes how to execute a specification using the command line interface that comes with
.
Features
provides a command line interface to execute specifications captured in HTML files. The command line interface has the following features:
- Execution of a single specification file
- Execution of a suite of specifications stored in a directory tree
GreenPepper command line
8. Developer examples
The Guice container system under development
Google Guice is an Inversion Of Control (IOC)
container get more information about it on Google Guice website
GuiceSystemUnderDevelopment code can be found in greenpepper-extension-guice: GuiceSystemUnderDevelopment.java
package com.greenpepper.extensions.guice;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.greenpepper.reflect.DefaultFixture;
import com.greenpepper.reflect.Fixture;
import com.greenpepper.systemunderdevelopment.DefaultSystemUnderDevelopment;
public class GuiceSystemUnderDevelopment extends DefaultSystemUnderDevelopment
{
private Injector injector;
private List<String> moduleNames = new ArrayList<String>();
public GuiceSystemUnderDevelopment()
{
}
public GuiceSystemUnderDevelopment(String... moduleNames)
{
Collections.addAll(this.moduleNames, moduleNames);
}
@Override
public Fixture getFixture(String name, String... params)
throws Throwable
{
lazilyInstantiateModulesAndInjector();
Fixture fixture;
if (params.length != 0)
{
fixture = super.getFixture(name, params);
injector.injectMembers(fixture.getTarget());
}
else
{
Class<?> klass = loadType(name).getUnderlyingClass();
Object target = injector.getInstance(klass);
fixture = new DefaultFixture(target);
}
return fixture;
}
private void lazilyInstantiateModulesAndInjector()
throws Exception
{
if (injector == null)
{
List<Module> modules = convertModuleNamesToModules();
injector = Guice.createInjector(modules);
}
}
private List<Module> convertModuleNamesToModules()
throws Exception
{
List<Module> modules = new ArrayList<Module>(moduleNames.size());
for (String moduleName : moduleNames)
{
Class<?> klass = loadType(moduleName).getUnderlyingClass();
modules.add((Module)klass.newInstance());
}
return modules;
}
public void addModules(String... moduleNames)
{
if (injector == null)
{
Collections.addAll(this.moduleNames, moduleNames);
}
else
{
throw new IllegalStateException("Cannot add module after a fixture has been instantiated");
}
}
}
Rest Fixture sample
 | Only available in Java
|
Here is an example of a fixture to test Rest web services.
RestFixture code can be found in greenpepper-extension-sandbox : RestFixture.java
RestFixture support GET POST DELETE PUT HEAD HTTP methods.
Available readable properties are responseHeader(headerName) responseBody responseStatus
| Import |
| com.greenpepper.extensions |
GET example
| GET |
/helloworld |
| check |
response status |
200 |
| check |
response header |
Content-Type |
text/plain |
| check |
response body |
Hello World |
| GET |
/unknown |
| check |
response status |
404 |
POST example (create resource)
| set request body |
Hello GreenPepper |
| GET |
/messages/0 |
| check |
response status |
200 |
| check |
response body |
Hello GreenPepper |
| set request header |
Accept |
as |
application/xml |
| GET |
/messages/0 |
| check |
response status |
200 |
| check |
response body |
<?xml version="1.0"><message id="0" value="Hello GreenPepper" />
|
PUT example (update resource)
| set request body |
Hello from GreenPepper |
| PUT |
/messages/0 |
| check |
response status |
200 |
| GET |
/messages/0 |
| check |
response body |
Hello from GreenPepper |
HEAD example (check if specified resource exists)
| HEAD |
/messages/0 |
| check |
response status |
200 |
| HEAD |
/messages/1 |
| check |
response status |
404 |
DELETE example
| DELETE |
/messages/0 |
| check |
response status |
200 |
| GET |
/messages/0 |
| check |
response status |
404 |
The Spring container system under development
Spring is an Inversion Of Control (IOC)
container get more information about it on Spring website
SpringSystemUnderDevelopment code can be found in greenpepper-extensions-spring: SpringSystemUnderDevelopment.java
package com.greenpepper.extensions.spring;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import com.greenpepper.reflect.DefaultFixture;
import com.greenpepper.reflect.Fixture;
import com.greenpepper.systemunderdevelopment.DefaultSystemUnderDevelopment;
public class SpringSystemUnderDevelopment extends DefaultSystemUnderDevelopment
{
private BeanFactory beanFactory;
public SpringSystemUnderDevelopment(String... applicationCtxes)
{
this.beanFactory = new GreenPepperXMLAplicationContext(applicationCtxes).getBeanFactory();
}
public SpringSystemUnderDevelopment(BeanFactory beanFactory)
{
this.beanFactory = beanFactory;
}
@Override
public Fixture getFixture(String fixtureName, String... params) throws Throwable
{
Fixture fixture;
if (params.length != 0)
{
fixture = super.getFixture(fixtureName, params);
}
else
{
try
{
fixture = new DefaultFixture(beanFactory.getBean(fixtureName));
}
catch (NoSuchBeanDefinitionException e)
{
fixture = new DefaultFixture(instantiateAsAutowiredBean(fixtureName));
}
}
return fixture;
}
private Object instantiateAsAutowiredBean(String fixtureName) throws Exception
{
Class fixtureClass = loadType(fixtureName).getUnderlyingClass();
BeanDefinition beanDef = new RootBeanDefinition(fixtureClass, RootBeanDefinition.AUTOWIRE_AUTODETECT);
DefaultListableBeanFactory fallFactory = new DefaultListableBeanFactory(beanFactory);
fallFactory.registerBeanDefinition(fixtureName, beanDef);
return fallFactory.getBean(fixtureName);
}
}
The Windsor castle container system under development
Windsor container is an Inversion Of Control (IOC)
container get more information about it on Windsor Castle website
 | New in GreenPepper .Net 1.3
|
| Import |
| GreenPepper.WindsorCastle.Fixtures |
A Castle basic Xml configuration file
<configuration>
<components>
<component id="Windsor.HelloWorld" type="GreenPepper.WindsorCastle.Fixtures.WindsorHelloWorld, GreenPepper.Extensions">
<parameters>
<injectedConstructor>hello constructor</injectedConstructor>
<injectedProperty>hello property</injectedProperty>
</parameters>
</component>
<component id="Windsor.component1"
type="GreenPepper.WindsorCastle.Fixtures.MyComponent1, GreenPepper.Extensions">
</component>
<component id="Windsor.component2"
type="GreenPepper.WindsorCastle.Fixtures.MyComponent2, GreenPepper.Extensions">
</component>
<component id="Windsor.AutoWired" type="GreenPepper.WindsorCastle.Fixtures.WindsorAutoWiredFixture, GreenPepper.Extensions" />
</components>
</configuration>
How to use Windsor system under development :
- You must add GreenPepper.Extensions.Castle.Windsor assembly in your configuration assemblies
- You must notify GreenPepper Core to use Windsor system under development : GreenPepper.WindsorCastle.WindsorSystemUnderDevelopment
(You can find more about system under development configuration here : Using a custom SystemUnderDevelopment)
- If you use a Windsor xml configuration file :
Just add the path to your Windsor configuration file in the system under development arguments
using System;
using Castle.MicroKernel;
using Castle.Windsor;
using GreenPepper.Fixtures;
using GreenPepper.Reflect;
namespace GreenPepper.WindsorCastle
{
public class WindsorSystemUnderDevelopment : PlainOldSystemUnderDevelopment
{
private IWindsorContainer container;
public WindsorSystemUnderDevelopment(IWindsorContainer container)
{
this.container = container;
}
public WindsorSystemUnderDevelopment():this(new WindsorContainer())
{
}
public WindsorSystemUnderDevelopment(params string[] xmlConfigurationFile)
: this(new WindsorContainer(xmlConfigurationFile[0]))
{
}
public override IFixture GetFixture(string fixtureName, params string[] parameters)
{
try
{
Type type = TypeForName(fixtureName);
container.AddComponent(type.FullName, type);
return new DefaultFixture(container.Resolve(type));
}
catch (Exception)
{
try
{
return new DefaultFixture(container.Resolve(fixtureName));
}
catch (ComponentNotFoundException)
{
return base.GetFixture(fixtureName, parameters);
}
}
}
}
}