/
Do With: Workflow validation (Developer)

Do With: Workflow validation (Developer)

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, GreenPepper 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

GreenPepper 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

GreenPepper will visually show the test result by coloring each testing cell:

GREEN

When the action has been executed successfully, GreenPepper color the cell(s) in green.

RED

If the action execution has failed, GreenPepper color the cell(s) in red.

YELLOW

If the system encounters an execution error, the cell is colored yellow and GreenPepper provides information about the error.

GRAY

When the action has been executed successfully, GreenPepper 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, GreenPepper 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, GreenPepper 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.

do with

bank

open checking account

12345-67890

under the name of

Spongebob


Squarepants

check

that balance of account

12345-67890

is

$0.00

end

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-67890Spongebob 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

Code for the Bank fixture
 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 Fixtures Conventions. It provides public instance methods openCheckingAccount and thatBalanceOfAccount to map respectively to the actions open checking account and that balance of account.

The fixture does not much except from delegating the processing to the application code, in this case the Bank class.

Code for the Bank application code
 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, GreenPepper 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 GreenPepper carries out in the following sequence of steps:

  1. It calls the method openCheckingAccountUnderTheNameOf() with the parameters 12345-67890, Spongebob and Squarepants
  2. 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 GreenPepper carries out in the following sequence of steps:

  1. It calls the method thatBalanceOfAccountIs() with the parameter 12345-67890 to get the value calculated by the system under test
  2. 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.

do with

bank

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

end

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:

Code for the Bank fixture
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.

do with

bank

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

end


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.

Related content

Do with: Workflow validation
Do with: Workflow validation
More like this
Rule For: Rule Validation
Rule For: Rule Validation
More like this
Scenario: Scenario specification
Scenario: Scenario specification
More like this
Scenario: Scenario specification (Developer)
Scenario: Scenario specification (Developer)
More like this
Rule For: Rule Validation (Developer)
Rule For: Rule Validation (Developer)
More like this
Documentation
Documentation
More like this