Fit Specification: Fixtures

 

Fit documents are owned by the customers and domain experts on your team.  The documents contain examples of how the program should work and Fit checks the examples against the actual program.  The examples are placed in tables with a special first row, but other than that, there are no limitations on how the examples are structured.  Customers should write tables in the way that comes most naturally to them.

 

Since there aren’t any limits to the way tables are structured, Fit can’t interpret the tables automatically.  It requires a fixture to interpret the table.  A fixture is a piece of code, written by the team’s programmers, that understands the structure of each type of table and how to check it against the actual program.

 

Contents:

 

Loading Fixtures. 1

Errors. 2

Interpreting Tables. 2

Default Interpretation. 3

Checking Cells. 4

Right and Wrong. 4

Empty Cells. 4

Unexpected Errors. 4

Expected Errors. 5

Expected Blank. 5

Cell HTML Converts to Text 6

Comparison Values Convert to HTML. 6

Type Conversion.. 7

HTML to Text Conversion. 7

Type Conversion. 7

Predefined Fixtures. 7

Run Results. 8

 

Loading Fixtures

 

The first row of a table is always the name of the fixture used to interpret that table.  There’s no special logic applied; if the first cell in the first row is not the correct fixture name, Fit won’t try to guess where it is.  (Note: we use the keyword “(missing)” to indicate a missing fixture name in the table below.)

 

fat.FixtureNameFixture

 

Table

FixtureName()

[exampleFixture]

exampleFixture

[exampleFixture]

[1] [2]

[3] [4]

exampleFixture

[] [exampleFixture]

(missing) 

[exampleFixture] [foo]

exampleFixture

[]

[exampleFixture]

(missing)

 

The fixture name is the full name of the code that will interpret the table.  (In Java, it’s a class.)  The fixture name is case sensitive and must be fully qualified (that is, include any namespace information).  All implementations of Fit use the “dot” notation of Java to qualify names.

 

fat.FixtureLoadFixture

 

FixtureName

LoadResult()

fat.ExampleFixture

loaded

fat.exampleFixture

error

Fat.ExampleFixture

error

ExampleFixture

error

fat.Example

error

 

Errors

 

When the fixture isn’t valid, Fit annotates the cell with an explanatory error message.  What makes something a fixture or not depends on which implementation of Fit you’re using.  In Java, for example, only classes that extend the “Fixture” class are fixtures.  Other languages might use the presence of specific methods to determine whether something is a fixture or not.

 

This error message may be displayed as part of additional information, such as an exception stack trace.

 

fat.FixtureLoadFixture

 

 

FixtureName

LoadResult()

ErrorMessage()

fat.ExampleFixture

loaded

(none)

NoSuchFixture

error

The fixture "NoSuchFixture" was not found.

fat.NotAFixture

error

"fat.NotAFixture” was found, but it’s not a fixture.

 

Case-sensitivity errors use the same error message as other “not found” errors.

 

fat.FixtureLoadFixture

 

 

FixtureName

LoadResult()

ErrorMessage()

fat.exampleFixture

error

The fixture "fat.exampleFixture" was not found.

 

 

 

NOTE TO IMPLEMENTORS:

The remainder of this document is incomplete.  The above examples should pass.  Don’t try to make any of the following examples pass, as they will surely change.

 

Interpreting Tables

 

By default, fixtures interpret tables from left to right and top to bottom.

 

fat.InterpretationOrderFixture

 

Table

InterpretationOrder()

[fat.ConcatenateFixture]

[top left] [top middle] [top right]

[bottom left] [bottom middle] [bottom right]

top left, top middle, top right, bottom left, bottom middle, bottom right

 

Although left-to-right and top-to-bottom is the default, fixtures may interpret tables in any order they please.  The fixture in the following example interprets tables column by column, from right to left and top to bottom.

 

fat.InterpretationOrderFixture

 

Table

InterpretationOrder()

[fat.ReverseConcatenateFixture]

[top left] [top middle] [top right]

[bottom left] [bottom middle] [bottom right]

top right, bottom right, top middle, bottom middle, top left, bottom left

 

Default Interpretation

 

Fit’s default interpretation of a cell is to mark it with the “ignore” standard annotation.  (See the annotation specification for details about standard annotations.)

 

fat.InterpreterFixture

 

 

InputTable

InterpretedTable()

RenderedOutput()

[fat.DoNothingFixture]

[left] [right]

<table>

  <tr><td>fat.DoNothingFixture</td></tr>

  <tr><td bgcolor="#efefef">left</td><td bgcolor="#efefef">right</td></tr>

</table>

 

 

If an error occurs while interpreting a cell, Fit marks it with the “error” annotation and includes whatever error information is available.  (In Java, this is a stack trace.)

 

??

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Fixtures may override the default interpretation and do whatever they wish.  The fixture in the following example marks all cells with the “right” standard annotation unless an error occurs, in which case it is marked with the “ignore” standard annotation.

 

??

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Checking Cells

 

Fit provides a standard service for checking a table cell’s correctness.  Given a table cell and a value, Fit compares the two and annotates the cell accordingly.  (This section assumes that the comparison value is a string.  See “Type Conversion,” below, for information about what happens when it’s not.)

 

Right and Wrong

 

When the table cell and the comparison value match, Fit marks the cell “right” using a standard annotation.  (See the annotation specification for more about standard annotations.)

 

fat.CheckFixture

 

 

Cell

ComparisonValue

Annotation()

<td>Something</td>

Something

right

 

When they don’t match, Fit marks the cell wrong and includes the comparison value.

 

fat.CheckFixture

 

 

 

 

Cell

ComparisonValue

Annotation()

Expected()

Actual()

<td>Something</td>

Something else

wrong

Something

Something else

 

Empty Cells

 

If the table cell is empty, Fit uses the “info” standard annotation to put the comparison value in the cell.

 

fat.CheckFixture

 

 

 

Cell

ComparisonValue

Annotation()

Info()

<td></td>

Anything

info

Anything

 

Unexpected Errors

 

If an error occurs while comparing the table cell to the fixture’s value, Fit uses the “error” standard annotation to put information about the error into the table.  If a stack trace or similar information is available, it is included.

 

The following examples use the keyword “(causes error)” in the “ComparisonValue” column to indicate that an error occurs.

 

fat.CheckFixture

 

 

Cell

ComparisonValue

Annotation()

<td>something</td>

(causes error)

error

 

If the table cell is empty, Fit uses the “info” standard annotation to put the word “error” into the table.  No error information (such as a stack trace) is included.

 

fat.CheckFixture

 

 

 

Cell

ComparisonValue

Annotation()

Info()

<td></td>

(causes error)

info

error

 

Expected Errors

 

If the table cell contains the word “error,” Fit assumes that an error was expected.  If an error occurs, Fit marks the cell right.  If it doesn’t, Fit marks the cell wrong.

 

fat.CheckFixture

 

 

 

 

Cell

ComparisonValue

Annotation()

Expected()

Actual()

<td>error</td>

(causes error)

right

n/a

n/a

<td>error</td>

Anything

wrong

error

Anything

 

Expected Blank

 

Fit does not support a standard “blank” keyword similar to the “error” keyword.  (Although the following example uses a “(blank)” keyword to indicate a blank comparison value, this keyword was programmed as part of fat.CheckFixture and is not a standard part of Fit.)

 

fat.CheckFixture

 

 

 

 

 

Cell

ComparisonValue

Annotation()

Expected()

Actual()

Info()

<td>blank</td>

(blank)

wrong

blank

(blank)

n/a

<td>blank</td>

Anything

wrong

blank

Anything

n/a

<td></td>

(blank)

info

n/a

n/a

(blank)

<td></td>

Anything

info

n/a

n/a

Anything

 

If a fixture wishes to allow blank values, it must handle this on its own.  A common approach is for the fixture to look for blank results and to convert them into a special keyword, such as “(blank)” or “(none)”.  Use this keyword in the table when a blank result is expected.

 

Cell HTML Converts to Text

 

The contents of the cell are converted from HTML to text as described in the parsing specification.

 

fat.CheckFixture

 

 

 

 

Cell

ComparisonValue

Annotation()

Expected()

Actual()

<td><i>anything</i></td>

anything

right

n/a

n/a

<td><i>anything</i></td>

<i>anything</i>

wrong

anything

<i>anything</i>

<td>&lt;i>anything&lt;/i></td>

<i>anything</i>

right

n/a

n/a

<td>&lt;i>anything&lt;/i></td>

anything

wrong

<i>anything</i>

anything

 

This conversion applies to blank cells and the “error” keyword as well.

 

fat.CheckFixture

 

 

 

Cell

ComparisonValue

Annotation()

Info()

<td>&nbsp;</td>

anything

info

anything

<td><font color="red">error</font></td>

(causes error)

right

n/a

 

Comparison Values Convert to HTML

 

When a comparison value is used in an annotation, it’s converted to HTML as described in the annotations specification.  See that section for examples.

 

Type Conversion

 

(to do)

 

Converting strings to objects

Converting objects to strings

Comparing objects

 

Predefined Fixtures

 

Fit includes several predefined fixtures.  Each fixture is described in a separate document, shown in the table below.

 

fat.ReferenceFixture

 

 

Description

Location

Result()

Primitive Fixture

primitive-fixture.html

 

Column Fixture

column-fixture.html

 

Row Fixture

row-fixture.html

 

Action Fixture

action-fixture.html

 

Summary Fixture

summary-fixture.html

 

 

Run Results

 

fit.Summary

 

 

 

 

 

(to do)

 

Be sure to include right, wrong, exception, and ignore counts in ‘check’ discussion

 

 


Check

Expected values specified in cells are tested for equality with actual values extracted from the program under test.

fat.Equals

type

x

y

=

boolean

true

TRUE

true

integer

00001

1

true

real

1000

1e3

true

string

abc

ABC

false

string

a b c

a b c

true

A sequence of values can be entered and checked as a single (composite) value.

fat.Equals

 

 

 

type

x

y

=

integers

1, 3, 5

01,03,05

true

integers

1, 3, 5

01,05,03

false

booleans

true, true, false

true, false

false

strings

a , b , c

a,b,c

true

Domain values can be constructed from cell contents. Equality comparisons will be subject to appropriate domain rules (i.e. delegated to the domain objects.)

fat.Equals

type

x

y

=

date

Jan 1, 1995

January 1, 1995

true

money

$10000

$10,000.00

true

Floating point numbers are checked to the precision that is normal in the host language. It is possible for a domain object to infer precision from the string representation of expected values. For example, [?]ScientificDouble checks equality to the precision implied by the number of significant digits in a value.

·         non-zeros -- 123.45 is 5 digits

·         zeros between non-zeros -- 100003 is 6 digits

·         zeros in the fraction part -- 12.20 is 4 digits

·         but not leading zeros -- 0001000 is 4 digits

·         and not exponent digits -- 6.02e23 is 3 digits

·         left argument (receiver) controles precision

fat.Equals

type

x

y

=

real

123.45

123.449

false

scientific

123.45

123.449

true

scientific

100003

100003.1

true

scientific

100003.1

100003

false

scientific

12.20

12.210

false

scientific

12.21

12.210

true

Improperly specified values may throw exceptions which are reported in the cell that contains the invalid number. Improper value detection is only as good as would be expected in the host language. (We are assuming that incorrectly converted values will lead to detected errors elsewhere.)

·         xyz is not an integer

·         10000000000000000000000000 may or may not be an integer

fat.Table

fat.Equals

 

type

x

integer

200

integer

xyz

 

fat.Color

white

white

white

white

white

white

white

yellow

Some character strings have special meaning outside of type conversion.

·         blank -- omit check, report value (reported in gray letters)

·         error -- expect an error

fat.Table

fat.Divide

 

 

x

y

divide()

100

2

50

100

2

 

100

0

error

100

0

 

 

fat.Color

white

white

white

white

white

white

white

white

green

white

white

gray/white

white

white

green

white

white

gray/white

The framework looks for parse support in different places.

·         fixture

·         domain object

·         type adapter

The framework will allow fixtures to implement custom parsing.

·         yea = true

·         nay = false


Fixture

By default cells are processed in order, by table, by row within tables, and by cell within rows. Distinct routines handle sequencing (plural) and interpretation (singular).

·         doTables -- sequence tables within a document

·         doTable -- interpret a table

·         doRows -- sequence rows within a table

·         doRow -- interpret a row

·         doCells -- sequence cells within a row

·         doCell -- interpret a row

The default interpretation of a cell is to mark it as ignored.

Cells contain givens or expected results. The fixture is responsible for distinguishing givens from expected results, checking expected results against actuals, and indicating the result with the background annotation as follows.

·         white -- no check wanted (blank input)

·         green -- right: expected equals actual

·         red -- wrong: expected not equal actual

·         yellow -- exception: trouble computing actual or comparing result

·         gray -- ignore: desired check not possible

Fixtures cooperate to count the number of each result.

·         counts accumulate between tables

·         counts are summarized as "# right, # wrong, # exceptions, # ignores".

·         runner fixtures (e.g. AllFiles) can control accumulation of counts

Fixtures cooperate to accumulate state that can be summarized at any point in the processing of a document.

·         state variables

·         state lifetime

·         state summary


PrimitiveFixture

The primitive fixture does not depend on TypeAdapter. Type specific functions handle all checking.

·         checkBoolean

·         checkInteger

·         checkFloat

·         checkString


ColumnFixture

A column fixture distinguishes givens from expected values by the form of the column head.

·         name is setter or field

·         name() is getter or field

·         camel case -- present value ( ) = presentValue()

·         deprecate execute()


RowFixture

A row fixture expects all rows to be expected values. The fixture is assumed to have access to actual rows which it pairs with expected rows.

·         name is field or getter

·         name() is getter

·         camel case

Rows are matched by comparing just enough values from the left most columns to get a unique match.

·         some given, none actual -- missing row

·         none given, some actual -- surplus rows

·         one given, one actual -- check remaining columns

·         many given, many actual -- match on more columns

Missing and surplus rows are marked as such in their first column

·         each counts as one wrong

·         surplus rows added to table in gray


ActionFixture

An action fixture distinguishes given from expected values based on keywords in the first column.

·         enter -- put given in setter or field

·         check -- check value with getter or field

·         press -- call action (no check other than for execptions)

·         start -- new actor

An actor represents some interface state such as the currently active window. The actor gives meaning to many of the words in the second column (field to be entered and buttons to be pressed).

·         actor persists between tables

·         initial actor is action fixture (subclass) itself

·         start with no argument specifies initial actor

Start could have various meanings depending on the nature of the interface being modeled.

·         create a new actor

·         return to an existing actor

Other actions, like press, can change the current actor.

·         replace the current actor with a new actor

·         replace the current actor with another preexisting actor

·         restore the previous actor

Subclasses of action fixture can add new action words.

·         camel case


Runner

A runner creates top-level Fixtures and provides them with parsed documents to be annotated.

·         top-level fixture is instance of Fixture

A runner retrieves and disposes of documents as appropriate to its environment. The FileRunner reads and writes html files.

·         input-file only -- default output

·         input-file output-file -- specific output

·         input-directory only -- default output in directory

·         input-directory output-directory -- default outputs in specific directory

·         index.html result summaries

·         - is standard in/out

A runner signals the presence of errors to its environment so that subsequent processing can be triggered.

·         exit status is sum of wrong and exceptions up to 255

·         main is factored to simplify [?]RunnerFixtures

A runner establishes run specific state that may influence loading and/or configuration of the program under test.

·         [?]AssemblyPath ???