[Aiml-programr-developers] Tests and Architecture
Nicholas H.Tollervey
ntoll at ntoll.org
Wed Sep 12 11:55:35 EDT 2007
Guys,
What follows is a summary of my thoughts on testing prior to sitting
down and writing them.
We're writing a library and as a result I'll define two sets of tests:
* UAT - that define the expected behaviour of the classes that we expect
other developers to have to use to write their applications
* Unit Tests - that additionally encompass the expected behaviour of the
wider classes / methods / areas of the library that we hope other
developers will not have to use.
As a result I'll do two things:
1. Specify our "public" classes that third party developers should use
to implement our library by means of example "use" cases written in code
2. Define the architecture behind these public classes so we can start
to write unit tests.
It is important to remember that I intend to unit test as locally to the
implementation of a method / class as possible. By this I mean that
there will not be any tests against the high-level "bot" class for the
"lower level" functionality of interpreting AIML tags (I'll test this
against the appropriate class(es)).
So onto some example use cases (I'll formalise these into proper Ruby
unit tests - the purpose of this email is to make public my testing
strategy so you guys can shout if you disagree and we can then modify as
needs be)...
I imagine a developer using our library should only have to deal with
five classes:
1. Bot - that encapsulates an instance of a particular bot.
2. User - that encapsulates all the information about a particular user
who is interacting with a "Bot"
3. Conversation - encapsulates and exchange between a particular "User"
and a "Bot"
4. Request - encapsulates an single item of raw input from a "User" to a
"Bot" as part of a "Conversation"
5 Response - encapsulates an item of output from a "Bot" to a "User" as
part of a "Conversation".
If I were to make a comparison with web-development our classes would
map like this:
Bot -> Website
User -> Client
Conversation -> Session
Request -> HTTP Request
Response -> HTML served back
I've done this on purpose as we intend to target Ruby on Rails as a
potential platform. We could also piggy back on-top of other ruby
enabled web technology (lighttp, apache etc) to provide a Bot server.
Having such an easy mapping from the world of www to bots will make this
simpler to carry out and easier for others to understand.
I'll UMLify these relationships when I get some time later this week.
Now onto a quick example of how I hope a developer might use these
classes, an improvisation in Ruby :-)
<code>
myBot = Bot.new() # for default settings or:
myBot = Bot.new(path) # where path is to a config.yaml file setting up
the bot to non default settings
myBot.ToYAML # bot's predicate list as YAML
# Attributes might include
myBot.Name # name of the bot
myBot.Botmaster # who the bot-master is
myBot.Size # number of categories in the graphmaster
# loading AIML
myBot.Learn(SomeRawAIML) # well formed obviously
myBot.Load("pathToAIMLFile(s)") # if an individual AIML file is
specified the file is loaded, if a directory all AIML files within it.
# User class:
myUser = User.new("Unique id") # where Unique id might be something like
a PK in a database so information can be retrieved.
myUser = User.new("Unique id", userconfig.yaml) # as above but with some
yaml passed that includes user predicate table and / or conversation history
myUser["Name"] # how to reference the user's predicates
myUser.Conversations[0] # most recent conversation
myUser.ToYAML # predicate list etc as YAML
# Conversation:
c = Conversation.new(myUser, myBot) # create a new conversation session
with the specified user and bot
c.Request[0] # the first thing said to the bot in this conversation
c.Response[0] # the first thing said to the user
c.StartedOn # Timestamp
c.TimeOut # a session timeout setting (any activity after this mount of
time results in the session closing)
c.Close # close the session
c.Open # re-open a session
c.Open? # is the session open?
# Request
req = Request.new("Some raw input") # ctor
req.StartedOn # timestamp
req.Response # either nil or the response object that was returned
req.User # who made the request (or nil)
req.Bot # "who" made the response (or nil)
req.Conversation # the session context for the request (or nil)
# Response
res = Response.new(req) # ctor
res.to_s # the output from the bot
res.FinishedOn # Timestamp. res.FinishedOn - req.StartedOn = Duration of
the request
res.Sentences[0] # First sentence of a multi-sentence response
res.User # User for whom the response is for
res.Bot # the Bot who created the response
res.Converstaion # the session context for the response
# sample session
myBot = Bot.new("config.yaml")
myUser = User.new("Default",someconfigYAML)
c = Conversation.new(myUser, myBot)
req = Request.new("Hi there!")
response = c.Speak(req)
return response.to_s
</code>
Nota Bene, the above code examples are off the top of my head and I'm
not sure how Rubyesque they are... Comments and suggestions would be
most welcome. :-)
Best wishes,
Nicholas
More information about the Aiml-programr-developers
mailing list