Skip to content

Instantly share code, notes, and snippets.

@gregturn
Created October 11, 2010 15:43
Show Gist options
  • Save gregturn/620737 to your computer and use it in GitHub Desktop.
Save gregturn/620737 to your computer and use it in GitHub Desktop.
import doctest
class BddDocTestRunner(doctest.DocTestRunner):
"""
This is a customized test runner. It is meant
to run code examples like DocTestRunner,
but if a line preceeds the code example
starting with '#', then it prints that
comment.
If the line starts with '#when', it is printed
out like a sentence, but with no outcome.
If the line starts with '#', but not '#when'
it is printed out indented, and with the
outcome.
"""
def report_start(self, out, test, example):
prior_line = example.lineno-1
line_before = test.docstring.splitlines()[prior_line]
if line_before.startswith("#"):
message = line_before[1:]
if line_before.startswith("#when"):
out("* %s\n" % message)
example.silent = True
example.indent = False
else:
out(" - %s: " % message)
example.silent = False
example.indent = True
else:
example.silent = True
example.indent = False
doctest.DocTestRunner(out, test, example)
def report_success(self, out, test, example, got):
if not example.silent:
out("ok\n")
if self._verbose:
if example.indent: out(" ")
out(">>> %s\n" % example.source[:-1])
def report_failure(self, out, test, example, got):
if not example.silent:
out("FAIL\n")
if self._verbose:
if example.indent: out(" ")
out(">>> %s\n" % example.source[:-1])
class ShoppingCart(object):
def __init__(self):
self.items = []
def add(self, item, price):
for cart_item in self.items:
# Since we found the item, we increment
# instead of append
if cart_item.item == item:
cart_item.q += 1
return self
# If we didn't find, then we append
self.items.append(Item(item, price))
return self
def item(self, index):
return self.items[index-1].item
def price(self, index):
return self.items[index-1].price * self.items[index-1].q
def total(self, sales_tax):
sum_price = sum([item.price*item.q for item in self.items])
return sum_price*(1.0 + sales_tax/100.0)
def __len__(self):
return sum([item.q for item in self.items])
class Item(object):
def __init__(self, item, price, q=1):
self.item = item
self.price = price
self.q = q
This scenario demonstrates a testable story.
First, we need to import the modules
>>> from cart import *
>>> cart = ShoppingCart()
#when we add an item
>>> cart.add("carton of milk", 2.50) #doctest:+ELLIPSIS
<cart.ShoppingCart object at ...>
#the first item is a carton of milk
>>> cart.item(1)
'carton of milk'
#the first price is $2.50
>>> cart.price(1)
2.5
#there is only one item
>>> len(cart)
1
This shopping cart let's us grab more than one
of a particular item.
#when we add a second carton of milk
>>> cart.add("carton of milk", 2.50) #doctest:+ELLIPSIS
<cart.ShoppingCart object at ...>
#the first item is still a carton of milk
>>> cart.item(1)
'carton of milk'
#but the price is now $5.00
>>> cart.price(1)
5.0
#and the cart now has 2 items
>>> len(cart)
2
#for a total (with 10% taxes) of $5.50
>>> cart.total(10.0)
5.5
if __name__ == "__main__":
from glob import glob
doctest.DocTestRunner = BddDocTestRunner
for file in glob("recipe28*.doctest"):
given = file[len("recipe28_"):]
given = given[:-len(".doctest")]
given = " ".join(given.split("_"))
print "==================================="
print "Given a %s..." % given
print "==================================="
doctest.testfile(file)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment