Easy Extend



                 




                                            Author: Kay Schluehr
                                            Date: 2007-07-24
                                            Version: 0.2


Introduction

In a Test Driven Development (TDD) approach to software development writing testcases is part of detail design and detail planning activities. What is sometimes missing in discussions about agility in particular about early phases, is an explorative element in software construction happening within live sessions. Those are available in languages supporting a REPL ( read-eval-print-loop) such as Lisp, Ruby, Python but also OCaml, Haskell or Scala. Instead of wasting information gained in these sessions after shutting them down an EE console uses a simple ( and optional ) session recorder and (re-)player and intercepts certain selected commands during re-play. This enables dirty testscripts and throwaway tests. EE console tests might apply when using a Python testframework is still too heavyweight.

1. Recorder & Player

    Console tests are based on recording and replaying interactive sessions. These sessions can be interrupted and continued. The report
    files might be edited.

2. Tests

    A console test has just minimal overhead. Well it's actually just the usuall assert statement and a single function to check for exceptions.

1. Recorder & Player

EasyExtend consoles provide two options, one for recording sessions and one for re-playing them:

usage: python fiber.py [options]

options:
  --rec                 use recording console to record interactive session
  --rep SESSION        
replays an interactive session

Recorded sessions are placed into the directory
Path          EasyExtend/fibers/<fiber-name>/fibercon

and they are equipped with the extension:
Recorded sessions are placed into the directory
Extension     ees

1.1 Recorder options

A peculiarity of the --rec option is that it keeps optional parameters. This is implemented by an optparse callback which is not shown in the optparse help for the same reason.

Command
Recorded console file
python fiber.py --rec
<fiber-name>.ees

Console name is used as report name.
python fiber.py --rec enum                     
   
<fiber-name>_<count>.ees

where count is the current number of ees files in the fibercon directory + 1.
python fiber.py --rec +suffix                 
<fiber-name>_suffix.ees

Freely selectable suffix that is appended to the console name.
python fiber.py --rec prefix+                  prefix_<fiber-name>.ees

Freely selectable prefix that is prepended to the console name.
python fiber.py --rec name
name

Arbitrary name without any restrictions.

1.2 Replaying a session

A session gets replayed when the --rep option is used. The --rep option requires a single mandatory parameter. The parameter is complementary to the parameter used for recording.
If for example
             python fiber.py --rec foo+

was used to create <fiber-name>_foo.ees
then
             python fiber.py --rep foo+

replays the recorded session. If enum was the option for --rec you need to know which report <fiber-name>_<count>.ees
accordingly has been generated. The appropriate value for count is always displayed in the session header.

So if you start Gallery with the option --rec enum. The session will look like

__________________________________________________________________________________________________________

 Gallery

 On Python 2.4.3 Stackless 3.1b3 060516 (#69, Sep  7 2006, 12:45:31) [MSC v.1310 32 bit (Intel)]
 Fiber documentation: www.fiber-space.de/EasyExtend/doc/gallery/gallery.html

 Creates session report Gallery_4.ees
__________________________________________________________________________________________________________

gal>

1.2.1  Interruption and continuation

Two commands are provided for interruption of a replayed session as well as its continuation.

Interrupt replay 
(without command execution)   
 ?
placed before prompt as in 

?>>> 1+2



  No execution of command              1+2

Continue replay  ! first character typed on the prompt

>>> !
Interrupt replay (with command execution)
 ?! placed before prompt as in 

?!>>> 1+2

Command 1+2 is executed before switching in interactive mode

The ? character works like a breakpoint. You can continue typing commands and proceed by typing !  Note that the recorded console is not implemented as a fiber and the singular '!' character is parsed as user input.

1.3 Record and replay

It is possible to record and replay a session at the same time. This is usefull when you interrupt a session using ? and continue edditing it.
Note that the --rec option must not have a parameter in this case but the --rep option only.
Command
Recorded and replayed console file
python fiber.py --rec --rep option
<fiber-name>_<option>.ees

Replays console session and re-records it.
This enables extending an existing recorded
session by new commands.

2. Tests

Console tests do not require a particular setup, a test suite or anything like this. Exceptions are captured by the REPL so everything that is needed is to extract and display testinformation. An obvious selection for this purpose are assert statements. Not that they are treated special within an interactive session. No magics is applied. Just the session player looks for assert and notifies whether an AssertionError or any other exception is raised. All assertions and their effects are listed after the replayed session.

__________________________________________________________________________________________________________

 Gallery

 On Python 2.4.3 Stackless 3.1b3 060516 (#69, Sep  7 2006, 12:45:31) [MSC v.1310 32 bit (Intel)]
 Fiber documentation: www.fiber-space.de/EasyExtend/doc/gallery/gallery.html

 Replay session Gallery.ees
__________________________________________________________________________________________________________

gal> import sys
gal> sys.last_value
Traceback (most recent call last):
  File "<input>", line 1, in ?
AttributeError: 'module' object has no attribute 'last_value'
?!gal> assert raises(AttributeError, lambda: 1/0)                   # assertion 1
Traceback (most recent call last):
  File "<input>", line 1, in ?
  File "C:\lang\python24\lib\site-packages\EasyExtend\eeconsole.py", line 482, in raises
    func(*args, **kwd)
  File "<input>", line 1, in <lambda>
ZeroDivisionError: integer division or modulo by zero
gal> !
gal> assert raises(ZeroDivisionError, lambda: 1/0)                 
# assertion 2
gal>
__________________________________________________________________________________________________


--------------------.
Recorded assertions |
-------------------------------------------------------------------------------------------------
Status |ees ln |repl ln| Assertion
-------+-------+-------+-------------------------------------------------------------------------
ERROR  | 11    | 14    | assert raises(AttributeError, lambda: 1/0)
OK     | 12    | 21    | assert raises(ZeroDivisionError, lambda: 1/0)
-------+-------+-------+--------------------------------------------------------------------------


In the Recorded assertions report section two types of line information is displayed
  • ees ln - line of assertion in the recorded ees report that gets replayed
  • repl ln - line of assertion in the replayed ees report

2.1 Test aid

Some additional test aids are usefull. These can be used in the process of evaluating assertions.The above example already shows the use of the function raises.

2.1.1 The function raises

raises( exception, func, *args, **kwd)
Returns True if func(*args, **kwd) raises exception otherwise False.
The raises function is used to turn a raised exception into a boolean value. It's counterpart in combination with assertions is the assertRaises method of the class TestCase in Pythons unittest framework.

2.1.2  __  a.k.a. double underscore

In console applications a single underscore command _ can be used to retrieve the last value. A double underscore command is used for similar purposes but it is used to retrieve the last relevant textual output in string form. It does not make a distinction between values and exceptions. With relevance  some exclusions are justified e.g. console prompts or certain line breaks.