I'm posting this message for 2 reasons. First, I'm still pretty new and shakey to the whole Acceptance Testing thing, and I'm hoping for some feedback on whether I'm on the right track. Second, although all the Agile literature talks about the importance of doing Acceptance Testing, there's very little in any of the books or out on the Web that helps with how to do it. If I am on the right track, this will be one more helpful item folks can find on a Google search.
The code below is basically a spike I wrote in a few hours last night to prove to myself and my team that it would be feasible to quickly create a simple, useful Acceptance Testing harness for our learning project. First, I wrote an example test script I would hope to be able to execute... =============== ?recipeListCount:0 !new ?name:"New Recipe" name:"PB&J" ?name:"PB&J" !save !close ?recipeListCount:1 !goToListItem 1 !openListItem ?name:"PB&J" =============== In this script, ? means test a value, ! means execute an action, and a line that starts with neither ? or ! is a value assignment. Next, here's the Python code I wrote to try to run the script. This was just proof of concept, so at this point, it just runs a single test script with the script file name hard coded. Also, for simplicty, the skeleton of the hypothetical application model object is, for now, in-line in the AT system code. =============== import string class RecipeOrgModel: recipeListCount = 0 name = "New Recipe" def new(self): pass def save(self): pass def close(self): pass def goToListItem(self,itemNum): pass def openListItem(self): pass class ParsedStatement: name = None value = "" def __init__(self,statementText,nameValuesDelim): delimPos = string.find(statementText,nameValuesDelim) if delimPos==-1: self.name = statementText else: self.name = statementText[0:delimPos] self.value = statementText[delimPos+1:] class TestSession: fileName="" lines = None model = RecipeOrgModel() def __init__(self,fileName): self.fileName = fileName def run(self): self.loadLines(self.fileName) for line in self.lines: if not self.processLine(line): break def loadLines(self, fileName): file = open(fileName) lines = file.readlines() file.close lines = map(string.strip,lines) self.lines = lines def processLine(self,line): print(line) if line[0]=='?': return( self.TestValue(line[1:]) ) elif line[0]=='!': self.DoAction(line[1:]) return 1 else: self.AssignValue(line) return 1 def TestValue(self,statement): parsed = ParsedStatement(statement,":") valueExpr = "self.model." + parsed.name valueIs = eval(valueExpr) valueExpected = eval(parsed.value) hasExpectedVal = (valueExpected == valueIs) if not hasExpectedVal: print(" - Expected " + str(parsed.value) + ", but got " + str(valueIs)) return(hasExpectedVal) def AssignValue(self,statement): parsed = ParsedStatement(statement,":") exec("self.model." + parsed.name + "=" + parsed.value) def DoAction(self,statement): parsed = ParsedStatement(statement," ") methodCall = "self.model." + parsed.name +"(" + parsed.value + ")" exec(methodCall) session = TestSession("test1.txt") session.run() =============== Note how the powerful, context-aware exec() and eval() procedures really help simplify the code. Finally, here's the output I get when I run this with the example script above saved in a file called test1.txt in the current directory. =============== ?recipeListCount:0 !new ?name:"New Recipe" name:"PB&J" ?name:"PB&J" !save !close ?recipeListCount:1 - Expected 1, but got 0 =============== And this result is pretty much what we expect to see - cool. -- http://mail.python.org/mailman/listinfo/python-list