doctests for interactive functions

Brian van den Broek broek at cc.umanitoba.ca
Thu Feb 8 14:20:03 EST 2007


Hi all,

I have a module of classes for getting input from the user that 
satisfies various constraints. For instance, one class is created with 
a menu of option, presents them to the user, and rejects any input 
other than a menu option; another ensures that the user's input is 
interpretable as an integer between specified bounds, etc.

It is a module I wrote up when in the early stages of learning Python. 
It's a bit ugly :-)  So, I am rewriting it, and this time also am 
putting in unit tests (I am using doctest).

Since the classes are for getting input interactively, a 
straightforward use of doctest is not going to work. (The tests won't 
run  automatically.) I've come up with  a way to make it work, but I 
would like to know from more experienced people if there are better 
ways that I am overlooking.

All classes take an optional argument input_function that determines 
how the class instance gets its input. If this is not provided, it 
defaults to raw_input. doctest tests reassign it so that they can be 
run automatically.


So, an actual interactive session might look like:

 >>> yn = IG.YesNo()
 >>> yn.get()
Yes or no?
What about?
You have entered 'What about?'.
You must enter a value in ['n', 'no', 'y', 'yes'].
(Case does not matter.)
Please try again.
Yes or no?
N
 >>> yn.data
False
 >>>


The corresponding doctest I've constructed looks like:

 >>> inputs = ['NO', 'What about?']
 >>> yn = IG.YesNo()
 >>> yn.get(input_function=lambda: inputs.pop())
Yes or no?
You have entered 'What about?'.
You must enter a value in ['n', 'no', 'y', 'yes'].
(Case does not matter.)
Please try again.
Yes or no?
 >>> yn.data
False


That works fine as a unit test. But, it doesn't score too well on the 
`executable documentation' metric, as there is the inputs.pop() in the 
way, and the user input doesn't make it on to the screen.

Is there any way to make the doctests look more like actual 
interactive sessions, while preserving their automatic runability?

Thanks and best,

Brian vdB




More information about the Python-list mailing list