Post on 06-Apr-2018
8/2/2019 Isis Bdd Integration
1/64
Apache Isis BDD Testing Guide
Acceptance Testing using BDD Frameworks
Version 0.2.0-incubating
8/2/2019 Isis Bdd Integration
2/64
2 Apache Isis BDD Testing Guide
Copyright 2010~2011 Dan Haywood
Permission is granted to make and distribute verbatim copies of this manual provided
that the copyright notice and this permission notice are preserved on all copies.
8/2/2019 Isis Bdd Integration
3/64
iii
Preface ........................................................................................................................................ v
1. Introduction ............................................................................................................................ 1
1.1. Behaviour-driven Development ....................................................................................... 1
1.2. Common Library ........................................................................................................... 2
1.3. Concordion Integration ................................................................................................... 3
1.4. FitNesse Integration ....................................................................................................... 5
2. Introducing the Framework .................................................................................................... 7
2.1. Introduction ................................................................................................................... 7
2.2. Fixtures ......................................................................................................................... 8
3. Bootstrapping & Teardown .................................................................................................... 9
3.1. Scenario Context ............................................................................................................ 9
3.2. Bootstrapping Isis ........................................................................................................ 10
3.3. Shutdown Isis .............................................................................................................. 11
4. Scenario Set Up ..................................................................................................................... 13
4.1. Logging On / Switching User ........................................................................................ 134.2. Date and Time Format ................................................................................................. 14
4.3. Setting Date and Time .................................................................................................. 16
4.4. Aliasing Services ......................................................................................................... 17
4.5. Setting Up Ob jects ....................................................................................................... 18
5. User Interaction .................................................................................................................... 21
5.1. Common ...................................................................................................................... 21
5.2. Supported Interactions .................................................................................................. 24
5.3. Concordion Integration ................................................................................................. 28
5.4. FitNesse Integration ..................................................................................................... 30
6. Asserting on Collections ........................................................................................................ 31
6.1. Check Collection Contents ............................................................................................ 31
6.2. Check List ................................................................................................................... 32
6.3. Alias Items In List ....................................................................................................... 34
6.4. VerifyRows (Concordion only) ..................................................................................... 35
7. Debugging ............................................................................................................................. 37
7.1. Run Viewer ................................................................................................................. 37
7.2. Debugging the Clock .................................................................................................... 38
7.3. Debugging the Object Store .......................................................................................... 38
7.4. Check Specifications Loaded (FitNesse only) ................................................................. 39
7.5. Debugging Services (FitNesse only) .............................................................................. 39
8. Hints and Tips ...................................................................................................................... 41
8.1. Structure your scenarios using Given/When/Then ........................................................... 41
8.2. Use a Story Page to collect together its set of Scenarios .................................................. 41
8.3. Use a Top-Level Suite Page to Collect a Set of Stories ........ ........ ........ ........ ........ ........ ... 42
8.4. Factor out common "Given"s ........................................................................................ 43
8.5. Use a Declarative Style for Page Names ........................................................................ 43
8.6. Separate In-Progress Stories from the Backlog ............................................................... 43
8.7. Organize Completed Stories by Component ................................................................... 44
8.8. Using the RunViewer fixture ........................................................................................ 44
8/2/2019 Isis Bdd Integration
4/64
Apache Isis BDD Testing Guide Contents
iv Apache Isis BDD Testing Guide
8.9. Set up Continuous Integration ....................................................................................... 44
A. Using XmlMind with Concordion ........ ........ ........ ........ ........ ........ ........ ........ ........ ......... ....... 45
A.1. Customization to support Concordion ........ ........ ........ ........ ........ ........ ........ ........ ......... .. 45
A.2. Creating a Document ................................................................................................... 46
A.3. Loading a Document ................................................................................................... 46
A.4. Navigating the Document ............................................................................................ 47
A.5. Knowing where you are ............................................................................................... 48
A.6. Selecting Content (eg to delete/move, or prior to adding new content) ............................. 49
A.7. Writing Content .......................................................................................................... 50
A.8. Inserting Content to existing Paragraphs ........ ........ ........ ........ ........ ........ ........ ......... ...... 52
A.9. Deleting Content ......................................................................................................... 55
A.10. Moving Content ........................................................................................................ 55
A.11. Adding concordion: and isis: attributes ............................................................... 55
8/2/2019 Isis Bdd Integration
5/64
v
Preface
Behaviour-driven development is a means to drive the development of an application through stories and
scenarios. These are expressed in a semi-formal textual form that can be understood (or indeed be written)
by the domain expert/business analyst, but which can then be used to directly exercise the system under
test as it is developed.
A number of frameworks exist to streamline this process. Generally these require the developer to write
glue code that acts as a bridge from the textual specification and the system under test.
TheBDD Viewermodule forApache Isis aims to allow BDD stories/scenarios to be written against the
domain model of an Isis application, without the developer having to write any glue code. It consists of
a common library that abstracts the interaction with the Isis metamodel, along with an integration (that
uses this common library) for one particular BDD framework, namely Concordion. There is also outline
coverage of the FitNesse integration (part ofisis-extras).
This user guide describes how to use the Concordion integration, along with details of the common library
so that other BDD frameworks can be integrated if required.
Apache Isis is licensed under Apache Software License v2. However, although Concordion itself licensed
under Apache License v2, it in turn depends upon an XML library called XOM, which unfortunately has
an LGPL 2.1 license. Apache projects are not allowed to have dependencies on LGPL projects.
The workaround that we have adopted is to exclude the XOM dependency in Isis' own pom.xml files,
meaning that they are compliant with Apache's licensing restrictions. However, any application code thatuses theBDD Viewermust explicitly add its own dependency to the XOM library. You'll find that the
pom.xml files generated by the quickstart archetype do indeed do this.
However, If you are unhappy to introduce this dependency to LGPL in your own code, then you will not
be able to use the Concordion integration.
http://www.gnu.org/licenses/lgpl-2.1.htmlhttp://www.gnu.org/licenses/lgpl-2.1.htmlhttp://www.apache.org/legal/resolved.html#category-xhttp://www.gnu.org/licenses/lgpl-2.1.htmlhttp://xom.nu/http://www.apache.org/licenses/LICENSE-2.0.htmlhttp://code.google.com/a/apache-extras.org/p/isis-extrashttp://fitnesse.org/http://concordion.org/8/2/2019 Isis Bdd Integration
6/64
8/2/2019 Isis Bdd Integration
7/64
1
Chapter 1
Introduction
An introduction to the idea of behaviour driven development, and the components that make up Isis'
integration with BDD frameworks.
1.1. Behaviour-driven Development
Prior to agile development, requirements gathering for systems was traditionally performed by business
analysts discussing requirements with the business, and expressing those requirements in documentation,
such as Word specs and perhaps spreadsheets. The acceptance criteria for such requirements were
often only sketched out, if at all; it would normally fall to the system testers to write acceptance tests
for the requirements, through a mixture of consulting the original (by now out-of-date) requirements
documentation and (as often as not) reverse-engineering the implementation.
Behaviour-driven development combines requirements capture and the acceptance test criteria in a single
form, through scenarios. As before, these requirements are in a form that a non-technical domain expert
from the business can understand. What differs though is that these scenarios can be used to directly
exercise the system, and so also represent the acceptance tests for the correct implementation of the
requirement. Moreover, the results of these tests are rendered in such a way that the business can
understand, and thus can help determine if the code is at fault or the test. Once implemented, the acceptance
tests also act as a regression suite for the system.
Scenario tests tend to act against a complete system, or sometimes at a subsystem-level. At any rate the
tests must be at a granularity that still makes sense to a non-technical businesss person. Compare this to
unit testing which exercises the behaviour / method of a single class.
Another commonly-used name for scenario testing is "agile acceptance testing". We've chosen to use the
term "scenario testing" though; it's a somewhat less clumsy term.
8/2/2019 Isis Bdd Integration
8/64
Introduction Common Library
2 Apache Isis BDD Testing Guide
1.2. Common Library
Apache Isis integrates with BDD frameworks through the services of a common library. The main concepts
that the common library exposes are:
the Scenario class, which provides the context for a single scenario of a story
the AliasRegistry, which allows a user-friendly alias (eg "fredCustomer") to be assigned to any
domain object and to be referenced subsequently
the StoryCell interface, which is an abstraction over a single element of data
The default implementation just wraps a java.lang.String, but some frameworks might provide
alternative implementations. For example, FitNesse has an implementation that maps to its internal
representation of a cell (fit.Parse class).
the CellBinding interface, which binds a column of a table to a property or to an alias
Many of the BDD frameworks (eg Concordion, FitNesse) encourage the use of tables as a means of
succinctly capturing scenario actions. This is reflected in the design of several of the classes provided
by the common library. The CellBinding interface is used to wire the values in the rows of the table
to the properties specified in the header.
Each CellBinding has a name (eg "on object") and some alternative names (eg "using"). This is
useful for BDD frameworks (such as FitNesse) where the provided text from the scenario needs to be
parsed in some way, matching up headings of columns within a tabular structure. The relevant methods
for BDD framework integrations that must do this are #matches(...), #setHeadColumn(..)
and #createHeadColumn(..). Note though that not every BDD framework integration needs this
particular feature; the Concordion integration for example calls pre-canned methods so the matching
is done simply by parameter position to these method.
The other main method provided by CellBinding is #captureCurrent(..). This is used (by all
framework integrations) to capture the current value for the column which this binding represents. For
example, for a column representing a property name, it might hold the value "firstName".
The library provides a default implementation ofCellBinding, though subclasses can override if
required. (For example, the FitNesse integration has its own implementation to map to its data structures
representing cells in the FIT tables).
One way of thinking of all these framework integrations is as a replacement presentation layer, hitting the
underlying domain model in the same way that the regular UI would. (This is why we call this module
is called the BDD viewer).
In the following chapter (Chapter 2,Introducing the Framework), details are provided of how the services
of the common library are used by each of the supported BDD framework integrations.
8/2/2019 Isis Bdd Integration
9/64
Introduction Concordion Integration
0.2.0-incubating 3
1.3. Concordion Integration
Introduction to Concordion
Concordion is a framework to enable scenario testing. It is implemented as a JUnit4 test runner, withthe test form being written in XHTML. The domain expert / business analyst authors new stories using
an XML editor; once executed as tests, the results are shown as the same XHTML document, annotated
to indicate which assertions have succeeded, and which have failed. It also creates an efficient feedback
loop; a Concordion test will "keep on going" even if it hits a failure. Thus the developer can identify
several issues and fix them in a single pass.
Concordion works using a "convention over configuration" approach, matching the XHTML text file with
a corresponding JUnit4 test run set up to run using Concordion's ConcordionRunner, The developer then
annotates the XHTML using special (namespaced) attributes in order identify the inputs to and expected
results of the test. This is used by the ConcordionRunner to call into corresponding methods in the test.
For example:
Suppose the analyst writes a scenario test called CustomerPlacesOrderScenario.xhtml.
In the XHTML the analyst has identified the details of the customer doing the ordering (customer ref
4321, say), the product being ordered (product code 1234), the fact that the customer initially has no
orders, and that the customer has no invoices outstanding. The test concludes with an assertion that
there is now an unfulfilled order for the customer, and that the customer now has an invoice to be paid.
The developer in turn edits the XHTML, identifying the customer and the product.
He then further edits the XHTML to call a method in the JUnit4 test representing the placing of an
order: placeOrder(), say. And he finishes by annotating the XHTML to make assertions about the
post conditions (unfulfilled order, new invoice to be paid etc).
Then, the developer writes a JUnit4 test alongside the XHTML; in this example it would be called
CustomerPlacesOrderScenario.java. Concordion calls into this JUnit4 test as it comes across
the annotations in the XHTML, and the JUnit4 test mediates with the system under test.
When the test runs, Concordion generates a copy of the XHTML in an output directory which can then
made available for inspection by the business analyst (eg published on a website).
The Concordion website has a good tutorial that demonstrates all the above, and can be completed in20~30 minutes.
One slight downside of using Concordion is in having to write tests in XHTML. One editor that we
recommend (commercial, but also with a free version for personal use) is XmlMind. More detailed
guidance is provided in Appendix A, Using XmlMind with Concordion.
How the Isis/Concordion Integration Works
Although you could test anApache Isis application using vanilla Concordion, this would entail you having
to write all the glue code yourself to interact with the domain objects. You would also need to encode the
http://xmlmind.net/http://concordion.org/Tutorial.htmlhttp://junit.org/http://concordion.org/8/2/2019 Isis Bdd Integration
10/64
Introduction Specifying the Output Directory
4 Apache Isis BDD Testing Guide
rules that are normally implemented by anIsis viewer, eg so that a hidden action cannot be invoked, and
an invalid value for a property cannot be set.
TheBDD viewerintegration provided byApache Isis works by providing a superclass for the JUnit4 test,
called AbstractIsisConcordionScenario. This exposes methods to perform all the tasks necessary
for exercising an application. The precise features are outlined in Chapter 2,Introducing the Framework.
For each XHTML scenario test, the developer writes subclasses the
AbstractIsisConcordionScenario, creating a name matching the scenario test (ie as per regular
Concordion). He then annotates the original XHTML, either calling directly into the inherited methods, or
writing small simple methods to delegate to these inherited methods as required. The Concordion website
has some hints and tips to help you find the right balance between these two approaches.
The XHTML script that you write should have the following namespace declaration:
...
The concordion namespace is the usual namespace required by Concordion. The isis namespace is
defined for a similar reason: to allow certain commands provided by the Isis/Concordion integration to
be invoked. More on this in Chapter 5, User Interaction.
Specifying the Output Directory
The directory for the generated output can be specified either:
by overriding the outputDir() method in AbstractIsisConcordionScenario; or
by setting the concordion.output.dir system property
If not specified, then the output directory defaults to /tmp/concordion.
Providing a CSS File
By default, Concordion will copy over the HTML for every scenario into the output directory, but it won't
copy over any CSS resources. If you want any CSS to be copied over, then:
override the customCssPackage() method in AbstractIsisConcordionScenario to return any
class in the package that holds the CSS file.
override thecustomCss()method to specify the name of the CSS file to copy over. If none is specified,
then concordion.css is used.
Configuring the Maven Surefire (test) plugin
The standard boilerplate to run Concordion underMaven is as follows:
http://concordion.org/Technique.html8/2/2019 Isis Bdd Integration
11/64
Introduction FitNesse Integration
0.2.0-incubating 5
org.apache.maven.plugins
maven-surefire-plugin
2.6
${project.build.directory}/concordion
**/*Scenario.java
**/Scenario*.java
y
There are a couple of points worth noting here.
first, the systemPropertyVariables element can be used to define the concordion.output.dir
system property, thereby specifying the directory for the generated output
second, the includes element can be used to only run classes with either a prefix or suffix
"Scenario". This allows common fixtures that have been factored out to be ignored.
An alternative approach is to have a top-level "suite" page that references all scenarios underneath
(probably grouped into stories). In this case the only test class that would be run included is the top-
level suite page. See Section 8.3, Use a Top-Level Suite Page to Collect a Set of Stories for further
discussion.
1.4. FitNesse Integration
Due to licensing restrictions, the FitNesse integration is not part ofApache Isis proper. However, it is
available on the companion Apache Extras' isis-extras site. Check that site for its release status (it is not
guaranteed to be in sync withIsis releases).
An outline of the FitNesse integration is provided here, if only to help compare and contrast the means by
which two different frameworks integrate with the common library. We hope that this will make it easier
to integrate other BDD frameworks in the future.
http://code.google.com/a/apache-extras.org/p/isis-extras/http://code.google.com/a/apache-extras.org/p/isis-extras/8/2/2019 Isis Bdd Integration
12/64
8/2/2019 Isis Bdd Integration
13/64
7
Chapter 2
Introducing the Framework
An introduction to the features provided by the framework. The subsequent chapters provide more
detailed coverage.
This chapter outlines the main features of the common library and their support by the framework-specific
integrations. The subsequent chapters provide more detailed coverage.
Note that due to licensing restrictions the FitNesse integration is not part ofApache Isis. Nevertheless, an
outline of the FitNesse integration is provided here, if only to help compare and contrast the means by
which two different frameworks integrate with the common library. We hope that this will make it easier
to integrate other BDD frameworks in the future.
2.1. Introduction
Broadly speaking, the framework provides the ability to bootstrap and initialize an Isis application and
allow the domain services and objects within that application to be exercised in the same way that a user
would interact with the system through a viewer.
The common library defines these abilities in terms of "fixture" classes, each of which performs a single
function. For example, there is a fixture class to bootstrapIsis, another to setup objects, and another to
describe the actual interactions by the user (check a property, invoke an action etc).
The fixture classes in the common library are oriented around a tabular approach to specifying behaviour,
making it easy to integrate frameworks such as FitNesse that adopt a table-oriented approach. Such an
approach equally supports frameworks such as Concordion that allow specifications to be written both as
tables and in free-form text. Admittedly, this does make the implementation of framework integrations
8/2/2019 Isis Bdd Integration
14/64
Introducing the Framework Fixtures
8 Apache Isis BDD Testing Guide
a little more complex than it might otherwise have been ... but this is only a problem for the framework
integrator, not the business analyst actually writing the scenarios.
2.2. Fixtures
The following chapters describe the fixtures available in detail. In summary, they are:
it bootstrap an instance of Apache Isis system using the in-memory object store (see Chapter 3,
Bootstrapping & Teardown);
setting up the system state ready for the scenario (see Chapter 4, Scenario Set Up):
specify the date/time format
initialize the system with a set of services, picked up from the isis.properties configuration file
allow fixtures (domain objects) to be installed into the object store
login a specific user
specify the date
allow the user to interact with services and domain objects (see Chapter 5, User Interaction):
asserting on the value of properties and the contents of collections
setting the value of a property (if valid) and adding to/removing from a collection (if valid)
invoking actions
asserting on the state of a class member (hidden, disabled or enabled)
assert on the state of properties
assert on the state of collections, either of an object, or returned from an action (see Chapter 6,Asserting
on Collections);
tearing down the system at the end of the test (see Chapter 3,Bootstrapping & Teardown)
There are also fixtures to help with debugging (see Chapter 7,Debugging).
For each fixture, you'll find there's a discussion about the capabilities provided by the common fixture,
and then details as to the support for that fixture by each of the BDD framework integrations (Concordion
and FitNesse).
8/2/2019 Isis Bdd Integration
15/64
9
Chapter 3
Bootstrapping & Teardown
The fixtures provided for bootstrapping at the start of a scenario, and tearing down at the end
In order to test an Apache Isis domain application, a running instance of an IsisSystem must be
bootstrapped, with the appropriate configuration.
3.1. Scenario Context
The common library provides a context object which holds a reference to a running IsisSystem.
Moreover, it tracks such things as the date/time that the scenario is running as, the user that is logged-in,
and managing the aliases of objects so that they can be interacted with.
Common
An instance of the Scenario class provides a context for the scenario. Framework integrations areexpected to instantiate this class, and then use it as the primary means to interact with the system.
The Scenario class has a public no-arg constructor. Instantiating the Scenario does not do anything;
it must also be bootstrapped (see Section 3.2, Bootstrapping Isis).
Concordion
The AbstractIsisConcordionScenario instantiates the Scenario object (from the common library)
automatically and binding it to a threadlocal. In addition, AbstractIsisConcordionScenario
provides methods that can be invoked from within XHTML (ie taking Strings).
8/2/2019 Isis Bdd Integration
16/64
Bootstrapping & Teardown FitNesse
10 Apache Isis BDD Testing Guide
Test cases should inherit from this abstract class, with the XHTML typically calling to the inherited
methods directly. The developer may optionally add small helper methods to be called from the XHTML
instead; these can factor out any boilerplate in the script.
FitNesse
Every FitNesse scenario must reference the ScenarioFixture fixture which provides the overall context
for the framework. This instantiates a Scenario object from the common library and binding it to a
thread-local.
Whereas other FitNesse fixtures are instantiated once per table, the ScenarioFixture is a FIT
DoFixture that exists for the duration of the test page. It should typically be referenced in the test suite's
setup page, and should appear first within this setup:
Scenario Fixture
3.2. Bootstrapping Isis
AnIsis runtime can be bootstrapped with a single call. This installs no-op implementations of some of
the main components, along with an in-memory object store.
Common
The Scenario#bootstrapIsis(String configDirectory, DeploymentType
deploymentType) is used to bootstrap theIsis runtime:
The specified config directory contains isis.properties config file, from which the services are
registered. Any fixtures in that properties file are ignored (the BDD integration requires that any
objects are created through the test scripts, see Section 4.5, Setting Up Objects and Chapter 5, User
Interaction).
The deployment type must be either EXPLORATION (meaning exploration actions are enabled) or
PROTOTYPE; no other values are valid).
Even if running in exploration mode, you must still logon (see Section 4.1, Logging On / SwitchingUser) in order to indicate which user account to run the scenario as.
Concordion
The AbstractIsisConcordionScenario class provides two overloaded versions of
bootstrapIsis(...) method:
#bootstrapIsis(String configDirectory, DeploymentType deploymentType)
Intended to be called from within an @Before setUp() method, when there's no particular need to
document the bootstrapping process within the scenario;
8/2/2019 Isis Bdd Integration
17/64
Bootstrapping & Teardown FitNesse
0.2.0-incubating 11
#bootstrapIsis(String configDirectory, String deploymentType):boolean
Intended to be called from the XHTML page, allowing the scenario document the bootstrapping
process. For example, to bootstrap in exploration mode, use:
Isis system bootstrapped
from config directory ../quickrun/config
and running in exploration mode.
The method always returns true, but any runtime exception will propagate to the generated page.
Whichever method is used, they both delegate to the common Scenario#bootstrapIsis(...)
method.
FitNesse
The BootstrapIsisConfiguredFromInMode fixture is used to bootstrapIsis. It takes the form:
Bootstrap Isis Configured From config
Directory
In Mode deployment
Type
This delegates to the common Scenario#bootstrapIsis(...) method.
3.3. Shutdown Isis
This fixture shuts down theIsis runtime, releasing memory and so on. A good place to put this is in the
test's teardown.
Common
The Scenario#shutdownIsis() method is used to shutdownIsis runtime.
Concordion
To shutdown Isis from within Concordion, use the
AbstractIsisConcordionScenario#shutdownIsis() method. This just delegates to the common
library's Scenario#shutdownIsis() method.
FitNesse
To shutdown Isis from FitNesse, use the ShutdownIsis fixture:
Shutdown Isis
8/2/2019 Isis Bdd Integration
18/64
Bootstrapping & Teardown FitNesse
12 Apache Isis BDD Testing Guide
This just delegates to the common library's Scenario#shutdownIsis() method.
8/2/2019 Isis Bdd Integration
19/64
13
Chapter 4
Scenario Set Up
Once Isis has been bootstrapped, the application state must be setup.
The setup fixtures are used to specify the initial state of the running application for a particular scenario's.
Specifically, this means setting up the services that define the application, the effective date and the
effective user. It also allows the setup of arbitrary objects (typically reference/static data objects; for
transactional objects see Chapter 5, User Interaction).
4.1. Logging On / Switching User
Used to specify the currently logged-on user. Should always be called near the top of the scenario, as
part of the "given". Can also be used for switching the current user later on in the scenario, eg to check
a workflow between different users.
Common
The common library provides two overloaded methods, depending on whether the roles for the user need
to be specified or not:
Scenario#logonAsOrSwitchUserTo(String userName)
Logs on / switch user to as a specific user.
Scenario#logonAsOrSwitchUserTo(String userName, List roleNames)
Logs on to a specific user, with specified roles. Part of the initialization for a particular scenario's setup,
and typically referenced in the test suite or scenario's own setup page.
8/2/2019 Isis Bdd Integration
20/64
Scenario Set Up Concordion
14 Apache Isis BDD Testing Guide
The username and roles are not validated against.
Concordion
The Concordion integration provides two sets of overloaded methods inAbstractIsisConcordionScenario:
#logonAs(String userName) and #logonAs(String userName, String roleListStr)
Intended to be called in the initial setup, as part of the scenario's "given".
#switchUserTo(String userName) and #switchUserTo(String userName, String
roleListStr)
(Optional); intended to be called later on in the scenario, eg, to test workflow.
Each of these is intended to be called from the XHTML. For example:
logged on as fsmith
The role list, if specified, should be comma-separated (any white space will be ignored).
FitNesse
The FitNesse integration provides two sets of overloaded fixtures:
Logon As user name
Logon As user name With Roles role list
Intended to be called in the initial setup, as part of the scenario's "given".
Switch User To user name
Switch User To user name With Roles role list
Optional; intended to be called later on in the scenario, eg, to test workflow.
The role list, if specified, should be comma-separated (any white space will be ignored).
4.2. Date and Time Format
BDD tests often rely on exact dates and/or time to be specified, but any such date/time must be specified
in text form. In order that tests do not fail when run with different locales, the common library allows a
date/time format to be specified.
This fixture is typically called only once in the scenario.
8/2/2019 Isis Bdd Integration
21/64
Scenario Set Up Common
0.2.0-incubating 15
Note
Date/time formats are based on the currently used locale. By default, Isis will use the current
locale. To change this, set the relevant locale within isis.properties. For example:
isis.locale=de_DE
Note
Dates are always intepreted strictly as UTC dates. This means that you shouldn't need to
worry about the timezone in which the tests are being run.
Common
The Scenario class provides two methods to specify date and time formats:
#usingDateFormat(String) is used to specify the date format.
If not called, the format defaults to "dd-MMM-yyyy", eg 02-Aug-2010.
#usingTimeFormat(String) is used to specify the time format.
If not called, the time format defaults to "hh:mm" (a 24 hour clock, eg 14:45 for 2.45pm)
Typically the scenario will have both date and also time specified (in Section 4.3, Setting Date and
Time), but assertions against domain objects will often care only about date, or may occasionally care
only about time. Therefore, whenever text representing a date must be parsed, the following is used:
parse against date+time (eg "dd-MMM-yyyy hh:mm")
if that fails, parse against just date (eg "dd-MMM-yyyy")
if that fails, parse against just time (eg "hh:mm")
Concordion
The AbstractIsisConcordionScenario provides two corresponding methods:
#usingDateFormat(String)
#usingTimeFormat(String)
For example:
The date/time is 2 mar
2007 09:20.
These just delegate to the corresponding methods in the Scenario class.
FitNesse
Not implemented at this time.
8/2/2019 Isis Bdd Integration
22/64
Scenario Set Up Setting Date and Time
16 Apache Isis BDD Testing Guide
4.3. Setting Date and Time
BDD scenarios often rely on an exact date and time, and the date/time that a scenario is being run upon
can be specified using this fixture. For example, with the date/time set, functionality that checks the a
property is defaulted to "today" can then be easily verified.
This fixture will typically be called only once in a scenario. However, more advanced scenarios might
require the date/time to be called different places. For example, a scenario might raise an Invoice, then
move the clock forward by 30 days to test functionality relating to the handling ofInvoices unpaid for
more than 28 days.
Common
The Scenario#dateAndTimeIs(String)method allows the scenario to specify the date and time.
Note that a String is passed in rather than a java.util.Date, so that the scenario can parse the dateaccording to the date/time format (see Section 4.2, Date and Time Format).
The fixture installs the FixtureClock as the implementation of the Clock singleton (in the applib).
Every call to the Clock will return the same date/time until the method is called again.
If this fixture is not called, then the default system clock is used, which gets the time from the host
computer. The Scenario#debugClock() method (Section 7.2, Debugging the Clock) can be used
to verify the clock state.
Concordion
The Concordion integration provides a number of overloaded methods, all designed to be called from
the XHTML:
#dateIs(String dateAndTimeStr)
#timeIs(String dateAndTimeStr)
For example:
The date/time
is 02-mar-2007 09:20.
The overloaded forms are just for convenience; sometimes the scenario will want to emphasis the date,
other times the time.
FitNesse
The FitNesse integration provides four versions (overloaded only so reads well in the page):
Date Is date and time
8/2/2019 Isis Bdd Integration
23/64
Scenario Set Up Aliasing Services
0.2.0-incubating 17
Date Is Now date and time
Time Is date and time
Time Is Now date and time
In each case the date/time provided is parsed against the format 'dd MMM yyyy hh:mm'
4.4. Aliasing Services
Specifies an alias to a service in order to invoke actions upon it. Typically this will be done for most if
not all of the registered repositories. The class name (as defined in isis.properties) is used as the
key; the alias defines a simple handle.
For example, a service com.mycompany.customers.defaults.CustomerRepositoryDefault
can be mapped to "customers".
Common
The common library provides two methods:
Scenario#getAliasRegistry()
AliasRegistry#aliasService(String aliasAs, String serviceClassName)
The BDD framework integration is expected to obtain the AliasRegistry from the Scenario, and then
use the AliasRegisty to register the alias.
Concordion
The Concordion integration provides a corresponding method, #aliasService(aliasAs, String
serviceClassName). This returns true if the service was found, false otherwise. Call within a table
to alias multiple services, for example:
Class Name
aliasAs
com.mycompany.myapp.objstore.dflt.claim.ClaimRepositoryDefault
claims
ok
com.mycompany.myapp.objstore.dflt.employee.EmployeeRepositoryDefault
employeesok
8/2/2019 Isis Bdd Integration
24/64
Scenario Set Up FitNesse
18 Apache Isis BDD Testing Guide
FitNesse
The FitNesse integration provides an implementation of a ColumnFixture, which is used as follows:
Alias Services
class name alias=
com.mycompany.myapp.objstore.dflt.claim.ClaimRepositoryDefaultclaims
4.5. Setting Up Objects
Virtually every scenario will require some initial objects to work on, be it a Customer, an Order or
just some reference data. However, by design the BDD viewer runs against an in-memory object store,
meaning that the application having been bootstrapped has nothing in its persistent object store.
This fixture, therefore, is used to create objects, and persists them to the object store. It is typically used
for immutable reference/standing data objects. It can also be to setup used for transaction/operational data
objects, though UsingIsisViewerForSetup, Chapter 5, User Interaction, is generallly to be preferred).
The DebugObjectStore fixture (Section 7.3, Debugging the Object Store) can be used to check the
state of objects created. You can also use the RunViewer fixture (Section 7.1, Run Viewer) to visually
inspect the state of the system using the DnD viewer.
Common
The common library support for setting up objects using the SetUpObjectsPeer class. This represents
the context for creating a set of objects all of the same type, and is usually called multiple times (eg
corresponding to a table structure in the scenario text itself).
The constructor for this class takes the following arguments:
AliasRegistryaliasRegistry
the alias registry which is used to lookup aliases to existing objects, and is populated with aliases for
the new created objects (if an alias binding is specified; see below).
StringclassName
This is the fully qualified class name of the object to be instantiated
SetUpObjectsPeer.Modemode
This is whether the object is to be persisted or not
CellBindingaliasBinding
8/2/2019 Isis Bdd Integration
25/64
Scenario Set Up Concordion
0.2.0-incubating 19
This object represents a binding to a cell that will hold the reference to each newly created object. It
can be left null if required.
Different methods are available for BDD framework integrations to call. Typically the BDD framework
is expected to setup header information (the names of the properties), and then process each row.
On the header of the table, the main method to call is:
#definePropertyOrAlias(String propertyNameOrAlias, int colNum)
This associates each column with a property of the class, or an alias for the object overall
When processing each row, typically the main methods to call are:
#addPropertyValueOrAlias(String propertyOrAliasValue)
This provides the value of each property of the object to be created, or the alias to know the object by
once created. The property value can either be an existing alias, else must be parseable (nb: Isis' ownvalue types itself perform the parsing, so there's no additional work to be done here)
#createObject()
This actually instantiates the object, either persistent or non-persistent as specified in the constructor,
and assigns it an alias
That said, there are some other public methods that are available for more complex integrations (notably:
FitNesse).
Concordion
The Concordion framework integration provides:
#setUpObject(String className, String aliasAs, String propertyName1, String
propertyName2, ...)
There are 10 overloaded versions of this method, to account for setting up different types of objects
that have up to 10 properties.
The method returns a string "ok" if has worked, otherwise it returns exception text. This might seem alittle odd, but allows a meaningful message to be shown in the XHTML.
#setUpObjectVarArgs(String className, String aliasAs, ...)
This (protected, not public) method is to cater for setting up objects that require more than 10
properties to be setup. In these cases, the developer should write their own method and call into the
#setUpObjectsVarargs(...) as required.
Note that this method should be called from the XHTML using isis:execute, not with
concordion:execute. The difference between the two is that isis:execute is called on the header
row as well as each body row, whereas concordion:execute only calls for each body row. The integration
8/2/2019 Isis Bdd Integration
26/64
Scenario Set Up FitNesse
20 Apache Isis BDD Testing Guide
requires the header row to be called in order to read the names of the properties to be used to initialize
the objects.
For example, here's how to setup a set of three Employee objects:
With Employees (com.mycompany.myapp.dom.employee.Employee):
Name
Approver
aliasAs
Fred Smith
Employee:Fred Smith
ok
Tom Brown
Employee:Fred Smith
Employee:Tom Brown
ok
Sam Jones
Employee:Fred Smith
Employee:Sam Jones
ok
In this example, we've chosen the convention that the alias is "Employee:FirstName LastName". This is
though just a convention; the alias could be anything you want.
FitNesse
The FitNesse integration uses the "Set Up Objects" table, called like so:
Set Up Objects com.mycompany.myapp.dom.employee.Employee
Name Approver alias as
Fred Smith Employee:Fred Smith
Tom Brown Employee:Fred Smith Employee:Tom Brown
Sam Jones Employee:Fred Smith Employee:Sam Jones
8/2/2019 Isis Bdd Integration
27/64
21
Chapter 5
User Interaction
Fixtures to describe interactions with the domain objects, mimicking the way in which an end-user
using an Isis viewer would interact.
The user interaction fixtures are the centrepiece of the BDD framework, simulating the interaction with
domain objects as if through a viewer. Using this fixtures, the scenario can interact with objects, check
their state, and alias referenced or returned objects for subsequent interactions
There is basically just one fixture used to describe user interactions, namely "Using Isis Viewer". There
is also a "For Setup" version (ie "Using Isis Viewer For Setup") that disables checks for visibility and
usability, making it easier to reuse functionality for setting up objects prior to a test scenario (the "given").
The DebugObjectStore fixture (Section 7.3, Debugging the Object Store) can be used to check the
state of objects created.
5.1. Common
The common library provides the UsingIsisViewerPeer class as a means by which the BDD
framework integration can interact withApache Isis runtime.
The UsingIsisViewerPeer class is generally called from within a table format, with each row
representing a specific interaction with the domain object. For example, a row might invoke an action, or
could check that a class member is unavailable.
Some interactions can be used to create or assign aliases to domain objects. For example, invoking a
non-void action will return a result. If the result is a domain object, then the alias can be used directly
subsequently in the scenario. If the result is a collection, then typically it is the scenario will make an
8/2/2019 Isis Bdd Integration
28/64
User Interaction Constructor
22 Apache Isis BDD Testing Guide
assertion on that collection using "Check List" (see Section 6.2, Check List) or alias an object out of
that list using "Alias Items In List" (see Section 6.3, Alias Items In List).
Constructor
Because UsingIsisViewerPeer is table-oriented, it uses CellBindings (see Section 1.2, Common
Library) to bind table headers to rows. The constructor takes the following parameters:
AliasRegistry
Used to access aliases for existing domain objects, and to register aliases for newly created/found
objects.
Perform.Mode
Whether to actually perform the interactions or not
CellBindings for each of the columns of the table.
Cell bindings are discussed immediately below.
Each of the framework integrations is expected to instantiate the UsingIsisViewerPeer at the
beginning of the table, and then call into the same instance for each row in the table.
Cell Bindings
The CellBindings passed into the constructor correspond to the standard columns of the table. Althoughall must be passed in, not all are needed for every interaction; in these cases the value can be left blank.
The CellBindings correspond to the following column names:
the "on object" column (can also use 'object', or 'on' if parsing column name provided by scenario text)
The (alias of) the object to interact with. A value must always be provided.
the "alias result as" column (can also use "result=", "alias=", "alias as")
The alias to assign the result of any interaction.
the "perform" column (can also use "do", "interaction", "interaction type")
the interaction to perform; discussed further below
the "on member" column (can also use "member", "using member", using")
the property, collection or action to use
the "that it" column (can also use "that", "verb")
optional qualifier for interactions that make checks; discussed below
the "with arguments" (can also "arguments", "parameters", "with parameters", "for", "value", "for
parameters", "value", "reference")
8/2/2019 Isis Bdd Integration
29/64
User Interaction Capture Current
0.2.0-incubating 23
the first argument, to the interaction, if any. It is possible to perform interactions with multiple
arguments (for example, invoking an action); but the UsingIsisViewerPeer needs to have a binding
for the first argument so that it can knows to interpret any following columns as further arguments.
The actual values that go into each of these columns are listed below (Section 5.2, Supported
Interactions).
The "Perform" Binding
Of all of the bindings discussed above, the "perform" binding is the most critical because it determines
the actual type of interaction to be performed. The valid values that can be provided for the "perform"
binding are:
check property / check collection / check add to collection / check remove from collection / check action
These are combined with a value in the "that it" binding; for example "check property XXX is hidden",or "check action XXX is valid for (some argument list)"
get property / set property / clear property
Read from or write to a collection. If setting, a single argument is required
get collection / add to collection / remove from collection
Read or write from a collection. If writing, a single argument is required
invoke action
Invoke action, with 0 to many arguments
get property default / get property choices / get action parameter default / get action choices
To enable the testing of the choicesXxx() and defaultXxx() supporting methods
Again, see the sections below (Section 5.2, Supported Interactions) for specifics..
Capture Current
Once the bindings have been setup, the fixture peer should be called for each row in the table.
The CellBinding class provides the #captureCurrent(...) method to capture the relevant
value for each row (with the CellBindings obtained directory from the Scenario class, eg
Scenario#getOnObjectBinding()).
For some framework integrations (eg Concordion) this design introduces a little more complexity than
strictly necessary, because the knowledge is already known as to which value relates to which binding.
But for other frameworks (eg FitNesse), the CellBinding provides a useful abstraction that makes it
easy to associate values with each column.
8/2/2019 Isis Bdd Integration
30/64
User Interaction Validate
24 Apache Isis BDD Testing Guide
Validate
Once the values for the current row have been captured, they can be validated. The
UsingIsisViewerPeer class provides the following methods for this:
#validateOnObject(): ObjectAdapter
Verifies that the current value of the "on object" binding corresponds to a known alias
#validateAliasAs(): String
Verifies that the current value of the "alias as" binding is not already in use
#validateOnMember(): ObjectMember
Verifies that the current value of the "on member" binding corresponds to the name of a member
(property name, collection name or action name) of the type of the object being interacted with (ie, as
specified in the "on object" binding)
#validatePerform(): Perform
Verifies that the current value of the "perform" binding corresponds to a known interaction type for
the particular type of member.
Again, see the sections below (Section 5.2, Supported Interactions) for specifics.
Perform Command
Once all the validation has been performed, the command can actually be performed. This is done with
the UsingIsisViewerPeer's #performCommand(ObjectAdapter onObject, String aliasAs,
ObjectMember onMember, Perform perform, List args) method.
5.2. Supported Interactions
The valid values for the various bindings when interacting with a class members are summarized in the
following sections.
Note:
the API provided by the common library is not type-safe; the values (as provided in ScenarioCell)
must match the values given here. While it is tempting to refactor the common library to use type
safe enums, this would move the need to translate scenario text into each and every BDD framework
integration. The API is probably correct as it is, even though it is reliant on the exact string phrases
that appear in the tables above.
Interaction with Properties
The valid values for the various bindings when interacting with a property are summarized below:
8/2/2019 Isis Bdd Integration
31/64
User Interaction Interaction with Properties
0.2.0-incubating 25
Table 5.1. Supported Interactions for Propertieson object alias as perform using
member
that it value
object alias check
property
property name is hidden
object alias checkproperty
property name is visible
object alias check
property
property name is disabled
object alias check
property
property name is enabled
object alias check
property
property name is empty
object alias check
property
property name is not empty
object alias check
property
property name contains value or object
alias
object alias check
property
property name does not
contain
value or object
alias
object alias check set
property
property name is valid
for
value or object
alias
object alias check set
property
property name is not
valid for
value or
object alias
object alias check clear
property
property name is valid
object alias check clear
property
property name is not valid
object alias set
property
property name value or object
alias
object alias clear
property
property name
object alias alias for
referenced
object
get
property
property name
object alias alias for
default object
get
property
default
property name
object alias alias for list of
choices
get
property
choices
property name
8/2/2019 Isis Bdd Integration
32/64
User Interaction Interacting with Collections
26 Apache Isis BDD Testing Guide
Obtaining a alias for the (value of) a property only makes sense if the property is a reference type, not
value type.
Interacting with Collections
The valid values for the various bindings when interacting with a collection are summarized below:
8/2/2019 Isis Bdd Integration
33/64
User Interaction Interacting with Collections
0.2.0-incubating 27
Table 5.2. Supported Interactions for Collections
on object alias as perform using
member
that it reference
object alias check
collection
collection
name
is hidden
object alias check
collection
collection
name
is visible
object alias check
collection
collection
name
is disabled
object alias check
collection
collection
name
is enabled
object alias check
collection
collection
name
is empty
object alias check
collection
collection
name
is not empty
object alias alias for
collection
get
collection
collection name
object alias check
collection
collection
name
contains object alias
object alias check
collection
collection
name
does not
contain
object alias
object alias check add
to
collection
collection
name
is valid
for
object alias
object alias check add
to
collection
collection
name
is not
valid for
object alias
object alias check
remove from
collection
collection
name
is valid
for
object alias
object alias check
remove from
collection
collection
name
is not
valid for
object alias
object alias add to
collection
collection
name
object alias
object alias remove from
collection
collection
name
object alias
8/2/2019 Isis Bdd Integration
34/64
User Interaction Interacting with Actions
28 Apache Isis BDD Testing Guide
Obtaining a reference to a collection allows objects to be aliased from within it, using Section 6.3, Alias
Items In List.
Interacting with Actions
The valid values for the various bindings when interacting with an action are summarized below:
Table 5.3. Supported Interactions for Actions
on object alias as perform using
member
that it with
arguments
(one or
more cols)
object alias check
action
action name is hidden
object alias check
action
action name is visible
object alias check
action
action name is disabled
object alias check
action
action name is enabled
object alias check
action
action name is valid
for
argument list
object alias check
action
action name is not
valid for
argument list
object alias alias for
returned
object
invoke
action
action name argument list
object alias alias for
parameter
defaut
get action
default
parameter
action name param number
(0-based)
object alias alias for list of parameter
choices
get actionparameter
choices
action name param number (0-based)
5.3. Concordion Integration
The Concordion framework integration provides a set of overloaded methods in
AbstractIsisConcordionScenario which call into the UsingIsisViewerPeer:
#usingIsisViewer(String onObject, String aliasResultAs, String perform,
String usingMember)
8/2/2019 Isis Bdd Integration
35/64
User Interaction Concordion Integration
0.2.0-incubating 29
For interactions that have no "that it" or arguments (eg "get collectoin recentlyPlacedOrders")
#usingIsisViewerThat(String onObject, String aliasResultAs, String perform,
String usingMember, String thatIt)
For interactions that require a "that it" but no arguments (eg, "check property firstName that it is
hidden")
#usingIsisViewerArgs(String onObject, String aliasResultAs, String perform,
String usingMember, String arg0, String arg1, ...)
For interactions that require arguments, but no "that it" (eg "invoke action placeOrder with arguments
arg1, arg2, arg3").
There are multiple overloaded versions of this method taking from 1 to 5 arguments.
#usingIsisViewerThatArgs(String onObject, String aliasResultAs, String
perform, String usingMember, String arg0, String arg1, ...)
For interactions that require a "that it" and also an argumetn or arguments (eg "check action placeOrder
is not valid for arg1, arg2, arg3)
There are multiple overloaded versions of this method taking from 1 to 5 arguments.
If there is a requirement for more than 5 arguments, then you can write your own method and delegate to
the (protected visibility) #usingIsisViewerThatArgsVarargs(...) method.
In all cases these methods return the string "ok", or return the text of an exception otherwise. This makes
them easy to embed
Do note that this method, if called from a table should be called from the XHTML using isis:execute,
not with concordion:execute. This is because the Isis/Concordion integration requires that the
first header row of the table also be processed (the concordion:execute only processes every row of
the body but skips the table).
For example:
on object
alias result as
perform
on member
that it
value
tomEmployee
tomsApprover
check property
8/2/2019 Isis Bdd Integration
36/64
User Interaction FitNesse Integration
30 Apache Isis BDD Testing Guide
Approver
is
Employee:Fred Smith
ok
It is also valid to call inline, ie outside of a table. In this case either isis:execute or
concordion:execute can be used; for simplicitly we recommend only ever using isis:execute.
For example:
With the employees service,
invoke action
All Employees and
alias the resulting list as list1;
ok
5.4. FitNesse Integration
The FitNesse integration provides a Using Isis Viewer (and also Using Isis Viewer For Setup)
fixture, to call in table format.
For example:
Using
Isis
Viewer
On
Object
Alias
Result
As
Perform alias
as
Fred
Smith
Employee:Fred
Smith
Tom
Brown
Employee:Fred
Smith
Employee:Tom
Brown
Sam
Jones
Employee:Fred
Smith
Employee:Sam
Jones
8/2/2019 Isis Bdd Integration
37/64
31
Chapter 6
Asserting on Collections
Fixtures to assert on the contents of a collection.
Although the user interaction fixtures (in Chapter 5, User Interaction) provide some capability to assert
on collections, those collections must belong to an object. It is therefore not possible to use them to assert
on the contents of a "free-standing" collection, that is, one that was returned as the result of invoking
an action. Those fixtures also do not provide any ability to simply assert on the contents of a collection(whether free-standing or owned by an object).
The fixtures in this chapter make it easy to assert on the contents of any collection. For owned collections,
there is some duplication with the user interactions fixtures; which you use is up to you.
6.1. Check Collection Contents
These fixtures are used to assert various facts about the contents of a collection.
They are typically used in the "Then", though can be helpful as a way of confirming/documenting a
"Given".
Common
The common library provides the CheckCollectionContentsPeer that provides the following
methods:
#isEmpty() returns true if the specified list is empty
#isNotEmpty() returns true if the specified list is not empty
8/2/2019 Isis Bdd Integration
38/64
8/2/2019 Isis Bdd Integration
39/64
Asserting on Collections Concordion
0.2.0-incubating 33
accepts CellBindings to represent the title and type columns. Specifically, the constructor takes the
following parameters:
AliasRegistry
a String for the list alias
CheckListPeer.CheckMode
the check can be EXACT (the contents of the collection must exactly match those provided in the table) or
NOT_EXACT (those objects specified must be within the collection, but there may be additional objects
also)
CellBinding for title
CellBinding for type (optional)
Concordion
The Concordion integration provides a single method #checkList(...):
#checkList(String listAlias, String title)
If the object is found then the method returns "ok".
Calling this method is an assertion that the specified list contains an object with the specified title.
It's possible to achieve broadly the same effect using other fixtures (either Section 6.1, Check
Collection Contents for both free-standing and owned collections, or the section called Interacting with
Collections for owned collections). However, the tabular form afforded by #checkList(...) may
make it more appropriate to use in some cases.
For example:
title
New - 2007-2-18
ok
New - 2007-2-14
ok
Note that the Concordion integration only supports only NOT_EXACT mode. An alternative is to
use Concordion's own verifyRows(...) mechanism, as described in Section 6.4, VerifyRows
(Concordion only).
8/2/2019 Isis Bdd Integration
40/64
Asserting on Collections FitNesse
34 Apache Isis BDD Testing Guide
FitNesse
The FitNesse integration provides two different table fixtures, Check List Contains (corresponding
to NOT_EXACT mode) and Check List Precisely Contains (corresponding to EXACT mode).
For example:
Check List Contains tomsClaimsAfterwards
Title
New - 2007-2-18
New - 2007-2-14
6.3. Alias Items In ListClosely related to CheckList Section 6.2, Check List, this fixture allows an alias to be associated with
items in a list. The list items are located by their title, and are presumed to exist. This fixture can therefore
also be used as a way of checking for presence of items in a list.
Common
The common library provides the AliasItemsInListPeer which can be used to check the contents of
a table, by title and optionally by type. It is designed to be called in a table format, and so has a constructor
that accepts CellBindings to represent the title, the type and alias columns. Specifically, the constructor
takes the following parameters:
AliasRegistry
a String for the list alias
CellBinding for title
CellBinding for type (optional)
CellBinding for alias
Concordion
The Concordion integration provides overloaded versions of#aliasItemsInList(...):
#aliasItemsInList(String listAlias, String title, String aliasAs)
#aliasItemsInList(String listAlias, String title, String type, String
aliasAs)
If successful, then the found object is aliased to the supplied alias and the method returns "ok".
For example, here is how to call the method inline:
8/2/2019 Isis Bdd Integration
41/64
Asserting on Collections FitNesse
0.2.0-incubating 35
Alias Tom Brown
in list1
as tomEmployee;
ok.
It is also possible to called from within a table.
FitNesse
The FitNesse integration provides the Alias Items In List fixture:
Alias Items In List list1
Title Alias As
Tom Brown tomEmployee
Sam Jones fredEmployee
6.4. VerifyRows (Concordion only)
Concordion provides its own mechanism for asserting on the contents of a collection, namely
concordion:verifyRows. The AbstractIsisConcordionScenario class therefore provides the
#getListContents(String listAlias) method that returns the contents of the object (as pojos)
as an Iterable.
For example:
Description
Date
claim 2
2007-2-18
claim 12007-2-14
Note that the value of properties can be asserted using this syntax.
8/2/2019 Isis Bdd Integration
42/64
8/2/2019 Isis Bdd Integration
43/64
37
Chapter 7
Debugging
Fixtures for debugging scenarios by inspecting the external or internal state of the Isis system.
There are a number of fixtures available to help you debug your BDD scenarios.
Note:
if using Concordion, the only fixture currently available is also the most useful, RunViewer (see
Section 7.1, Run Viewer).
7.1. Run Viewer
When encountered in the scenario text, this fixture runs the DnD viewer. This is a great way to inspect
the state of the system, for example if a test is failing and you can't see why.
Common
This fixture is provided by the Scenario#runViewer() method.
Concordion
The Concordion integration provides this fixture by the
AbstractIsisConcordionScenario#runViewer() method. This simply delegates to the common
library.
For example:
8/2/2019 Isis Bdd Integration
44/64
Debugging FitNesse
38 Apache Isis BDD Testing Guide
run viewer
FitNesse
The FitNesse integration provides the Run Viewer fixture, called as a simple 1-cell table:
Run Viewer
7.2. Debugging the Clock
Reads the current value of the clock. Useful for debugging and diagnostics.
Common
The common library provides the DebugClockPeer class.
Concordion
Not yet implemented.
FitNesse
Provided by the Debug Clock fixture.
7.3. Debugging the Object Store
This fixture dumps the contents of the object store. Useful for debugging setup (through SetupObjects,
Section 4.5, Setting Up Objects, and UsingIsisViewerForSetup, Chapter 5, User Interaction).
Common
The common library provides the DebugObjectStorePeer class.
Concordion
Not yet implemented.
FitNesse
Provided by the Debug Object Store fixture.
8/2/2019 Isis Bdd Integration
45/64
Debugging Check Specifications Loaded (FitNesse only)
0.2.0-incubating 39
7.4. Check Specifications Loaded (FitNesse only)
Verifies that the listed ObjectSpecifications have been loaded into the metamodel.
Provided by the Check Specifications Loaded fixture.
7.5. Debugging Services (FitNesse only)
Lists service class names, as picked up from configuration. Useful with AliasServices (see Section 4.4,
Aliasing Services).
Provided by the Debugging Services fixture.
8/2/2019 Isis Bdd Integration
46/64
8/2/2019 Isis Bdd Integration
47/64
41
Chapter 8
Hints and Tips
Hints, tips and suggestions for writing your own stories and scenarios.
8.1. Structure your scenarios using Given/When/Then
A standard template for organizing structuring tests is given/when/then1:
given ... the system is in this particular state
when ... this interesting thing happens
then ... these are the consequences
This structure is readily understood by non-technical business users, and helps them (and the team) focus
on the point of the scenario.
For example:
if using Concordion, use headers to separate out the different regions of the page.
if using FitNesse, use its wiki syntax (eg !1 and !2) to create headers for the different regions of the
page; see the FitNesse user guide for more details.
8.2. Use a Story Page to collect together its set of Scenarios
Part of estimating the size of a story includes identifying the acceptance criteria for each of its scenarios.
These can be created as children of the story page as placeholders, so that the story page becomes a suite.
1As first described, I believe, by Dan North in a blog post, Introducing BDD.
http://dannorth.net/introducing-bddhttp://fitnesse.org/FitNesse.UserGuide.MarkupHeaders8/2/2019 Isis Bdd Integration
48/64
Hints and Tips Use a Top-Level Suite Page to Collect a Set of Stories
42 Apache Isis BDD Testing Guide
The child scenarios can be fleshed out as required with plain text during the estimation meeting, and with
interactions and assertions (ie actual data) once the iteration starts.
For the story page itself, the "as a ... I want ... so that... " template is a good way to summarize the intent
of the story.
For example:
if using Concordion, then the story page can easily reference each of the scenarios using Concordion's
concordion:run command. You might also want to have one directory per story, and call this page
Index.html.
For example:
New Claim Stories
new claim defaults ok
new claim shows up for claimant
if using FitNesse:
the !include instruction can be used to list include all referenced scenarios for a story as a "subwiki".
the !contents instruction canbe used to create a table-of-contents for these scenarios.
8.3. Use a Top-Level Suite Page to Collect a Set of Stories
In the same way that a story can aggregate scenarios, so can a top-level page aggregate all stories. This
can act as a starting point for a whole suite of tests, eg for a single iteration or a single component(more discussion on this in Section 8.6, Separate In-Progress Stories from the Backlog and Section 8.7,
Organize Completed Stories by Component).
For example, if using Concordion you could adopt the convention that the top level suite page is called
"AllStories.html". If so, the Maven surefire plugin could be configured to only run that page:
maven-surefire-plugin
...
**/AllStories.java
http://fitnesse.org/FitNesse.UserGuide.MarkupContentshttp://fitnesse.org/FitNesse.UserGuide.MarkupPageInclude8/2/2019 Isis Bdd Integration
49/64
Hints and Tips Factor out common "Given"s
0.2.0-incubating 43
8.4. Factor out common "Given"s
Just like code, scenarios need to be actively managed, because if the scenarios become hard to maintain,
they'll end up being deleted. In fact, we probably should take even more care with the scenarios than the
code if they represent the primary documentation of the behaviour of the system.
In terms of size, the "given" is far larger than either the "when" or the "then", and therefore this is the
area where scenario text can quickly become unmaintainable. So instead, try to factor out your givens
into separate pages.
For example:
if using Concordion, you can use 's with a concordion:run command to reference another
page.
if using FitNesse, then use it's !include directive to assemble the pages you need
You can do this both within a single story and also across stories; anywhere that there is some degree of
commonality. All scenarios require bootstrapping, and many scenarios won't care about the current user
or date/time. They may also use much of the same setup of reference data objects. All these scenarios
could therefore share a common fixture for all of this setup.
8.5. Use a Declarative Style for Page Names
When factoring out "given"s (see Section 8.4, Factor out common "Given"s), or indeed when writing
the "when"s and the "then"s, use a declarative style for the pages. The page should describe what it does,
not how it does it.
For example, a good page name would be "SetUpCountries". It's clear that this will set up all Country
reference data classes. Perhaps even better would be to name the page "AllCountries", because this has
a declarative form (explains what is the outcome of the referencing page) rather than imperative (telling
the system to set up some Countrys).
Such pages can be nested. For example, AllCountries page could be included into an "AllReferenceData"
page. For transaction data, we could have a page "JoeBloggsCustomer"; another one again could be
"JoeBloggsFiveOrders".
8.6. Separate In-Progress Stories from the Backlog
If you are using an agile methodology then you will be implementing the scenarios for a number of stories
per iteration; the remainder will be in a backlog. When you select a scenario for implementation, create
http://fitnesse.org/FitNesse.UserGuide.MarkupPageIncludehttp://fitnesse.org/FitNesse.UserGuide.MarkupPageInclude8/2/2019 Isis Bdd Integration
50/64
Hints and Tips Organize Completed Stories by Component
44 Apache Isis BDD Testing Guide
a new page for it in a "CurrentIteration" suite. The objective for the team is therefore to get the entire
CurrentIteration suite green.
Other stories that you may have identified but not selected for the iteration can remain in a Backlog suite.
8.7. Organize Completed Stories by Component
Once you have completed an iteration and implements all the scenarios of a particular story, move that
story out to the relevant component that the story relates to. The scenario tests for stories ultimately are
the documentation of the behaviour of the system. A year on you won't remember (and won't care) which
iteration you implemented a scenario, you'll be searching for it by the component whose behaviour you
want to understand.
8.8. Using the RunViewer fixture
The "given" can often be the hardest part to get setup. To check it, we can use the RunViewer fixture
(see Section 7.1, Run Viewer). This will run up the drag-n-drop viewer at the specified point in the test;
a visual equivalent ofSystem.out.println(), really. We can therefore take the Given page and add
a RunViewer fixture at the end.
Note that to do this you must temporarily mark the Given page as a test page.
8.9. Set up Continuous Integration
SinceIsis is a Maven application, it is easy enough to configure it to run under a CI server, such as Hudson.
You could then use the Hudson HTML Publisher plugin to publish the generated results onto a website.
This way they can be easily inspected at any time by your domain experts / business analysts.
http://wiki.hudson-ci.org/display/HUDSON/HTML+Publisher+Pluginhttp://wiki.hudson-ci.org/display/HUDSON/HTML+Publisher+Pluginhttp://fitnesse.org/FitNesse.UserGuide.PagePropertieshttp://wiki.hudson-ci.org/display/HUDSON/HTML+Publisher+Pluginhttp://hudson-ci.org/http://fitnesse.org/FitNesse.UserGuide.PageProperties8/2/2019 Isis Bdd Integration
51/64
45
Appendix A. Using XmlMind with
Concordion
How to use XmlMind to write tests for the Isis/Concordion integration.
XmlMind is an editor for writing structured XML documents, including XHTML documents as used by
Concordion. XmlMind is designed to be used by non-technical as well as developers, and provides a
WordProcessor-like interface. That said, like any tool it has learning curve. This document describes the
most commonly-used features.
XmlMind is a Java application, so runs on Windows as well as a number of other operating systems. It
can be downloaded from http://xmlmind.com. There are two editions, professional and personal. All the
features described in this appendix here are available in the personal edition.
A.1. Customization to support Concordion
XmlMind ships with the DTD for XHTML, along with a corresponding CSS file which is used for the
look-n-feel when editing. In order to make XmlMind support Concordion namespaces, we customize both
its XHTML DTD and CSS file.Cr
Download xhtml1-strict.dtd and copy into addon/config/xhtml/dtd/1.0 (relative to the XmlMindinstallation directory).
This updated version of the DTD defines the concordion and isis namespaces and specifies
additional attributes for certain elements
Download xtml.css and copy into addon/config/xhtml/css (again, relative to the XmlMind
installation directory).
This updated version of the CSS highlights those elements on the page that have been annotated using
the concordion or isis attributes.
The DTD customization specifies the following valid concordion attributes:
on any HTML element
concordion:assertEquals
concordion:set
concordion:assertTrue
concordion:assertFalse
isis:execute
http://incubator.apache.org/isis/viewer/bdd/xmlmind/xhtml.csshttp://incubator.apache.org/isis/viewer/bdd/xmlmind/xhtml.csshttp://incubator.apache.org/isis/viewer/bdd/xmlmind/xhtml1-strict.dtdhttp://xmlmind.com/8/2/2019 Isis Bdd Integration
52/64
Using XmlMind with Concordion Creating a Document
46 Apache Isis BDD Testing Guide
Use instead ofconcordion:execute
concordion:verifyRows
concordion:run
These can be specified in the same way as any other attribute.
A.2. Creating a Document
Both Concordion and XmlMind require that the test file is XHTML, meaning that the XML pragma is
required. XmlMind also requires that the file specifies the XHTML doctype, and Concordion also requires
its namespace to be declared.
Use File > New Documentto create anXHTML Strictdocument; this will set up the DTD and namespaces
required. Save the file as .xhtml; if running on Windows you can then setup XmlMind is a registered
editor for this suffix.
Once the file has been created, we recommend that you change the DOCTYPE entry to reference DTDs
stored locally. This will substantially speed up the execution time for Concordion, and also allow tests to
be run offline (ie not connected to the internet). So, instead of:
...
8/2/2019 Isis Bdd Integration
53/64
Using XmlMind with Concordion Navigating the Document
0.2.0-incubating 47
A.4. Navigating the Document
To navigate around, use up arrow, down arrow, pg up, pg down to move around.
It is also possible to navigate by opening up an alternative view to inspect the raw XHTML, using View
> Addto bring up a dialog:
The new view is shown in the location specified in the dialog:
8/2/2019 Isis Bdd Integration
54/64
Using XmlMind with Concordion Knowing where you are
48 Apache Isis BDD Testing Guide
This can then be used to navigate, collapsing sections if needed.
A.5. Knowing where you are
The position within the document is shown as a XPath like expression. If the unstyled view is open, then
the current position is highlighted (even if the section is collapsed). In the styled view the current cursor
position is shown just as in a regular word processor.
8/2/2019 Isis Bdd Integration
55/64
Using XmlMind with Concordion Selecting Content (eg to delete/move, or prior to adding new
content)
0.2.0-incubating 49
A.6. Selecting Content (eg to delete/move, or prior to adding new
content)
The XMLMind editor understands the structure of XHTML documents, and will only let you enter content
where it is valid to do so. What you can do (in terms of edits) therefore depends on where you are inthe document.
Use Select > Select Parent(ctrl+up) to successively select larger segments of the document; and Select
> Select Child(ctrl+down) to selects smaller segments.
8/2/2019 Isis Bdd Integration
56/64
Using XmlMind with Concordion Writing Content
50 Apache Isis BDD Testing Guide
A.7. Writing Content
Adding New Paragraphs
To modify the content in a paragraph, just start writing! Hitting enter will start a new paragraph; deletewill join two paragraphs together. Behind the scenes the
elements are added.
Adding a new heading (H1, H2) section etc
In general, useEdit > Insert After(ctrl+J) after to add new content after the current location, andEdit >
Insert Before (ctrl+H) to insert before. This will bring up a list of valid elements in the top right:
8/2/2019 Isis Bdd Integration
57/64
Using XmlMind with Concordion Adding lists
0.2.0-incubating 51
New sections , are valid after any other heading or indeed after a paragraph:
. Note that
XHTML does not require proper nesting of sections (though it's probably advisable to do so):
Adding lists
Adding lists are added as for any element: use ctrl+J and then select (unordered list) or
(ordered lists). Youll get the first for free. Create new list items by selecting the current list item
(ctrl+up as far as required) then use ctrl+J.
If you want to terminate the list, then select the current list (ctrl+up), then ctrl+J and select
for next
paragraph.
Adding and Altering Tables
UseEdit > Insert After(orEdit > Insert Before), and then select one of the table elements:
table
table (head_column)
to include a header column (on the left hand side)
table (head_row)
to include a header row
table (head_row_column)
to include a header row and column
For example, head_row:
8/2/2019 Isis Bdd Integration
58/64
Using XmlMind with Concordion Inserting Content to existing Paragraphs
52 Apache Isis BDD Testing Guide
This will generate an initial table:
Then use the XHTML menu to add columns/rows as required:
A.8. Inserting Content to existing Paragraphs
Formatting Existing Paragraphs
In contrast,Edit > Insert(ctrl+I) within a paragraph will only bring up elements that are valid within
that paragraph, such as or :
8/2/2019 Isis Bdd Integration
59/64
Using XmlMind with Concordion Formatting Existing Paragraphs
0.2.0-incubating 53
That said, for adding tags within a paragraph (such as emboldening or emphasis), it is generally easier
to write the words and then use Edit > Convert (wrap). First, highlight the words by holding shift and
then navigating as usual (eg shift+left, shift+right). Then, useEdit>Convert(wrap) to add the emphasis,
embolden etc:
resulting in something like:
8/2/2019 Isis Bdd Integration
60/64
Using XmlMind with Concordion Adding Images (and Attributes)
54 Apache Isis BDD Testing Guide
Adding Images (and Attributes)
To add an image, useEdit > Insertand enter an element, re