In this step, we'll make Eliza testable. Or to be precise, we'll make Eliza's
patterns testable. We're going to do this because we want an automated way
of ensuring that any new code we write (specifically the new synonyms we're going
to add) doesn't break existing functionality. If Eliza was a small app, we could
test it manually. But in its current form (and like all real complex
apps), we need an automated way to ensure we don't introduce bugs
as a result of adding new code.
We'll modify our Eliza Visual Studio solution so that instead
of containing a single project, it will contain three projects:
Splitting the solution into multiple projectsOur original Visual Studio solution looked like this:![]() ![]() ![]() Adding the tester programNow we'll add the tester console application project, ElizaTest, to our solution. Like ElizaMain, ElizaTest will contain a reference to the Eliza project so it can use the Eliza class. However, instead of allowing a user to chat with Eliza, ElizaTest will give a pattern a pre-determined string and check whether it returns the expected response. If the expected response is received, the test will be deemed to have passed. Otherwise, the test will have failed. We'll use the .NET Debug.Assert() method to assert (check) if the result returned by GetResponse() is the expected one. ElizaTest will display the name of each test as it runs. If a test fails, Debug.Assert() will display a message box that shows the stack trace and the point of failure. If all tests succeed, ElizaTest will display a summary at the end of its execution. Let's add the console application project ElizaTest to our solution. Notice the reference to the Eliza project.![]() ![]() Writing our first testLet's begin by testing the "AM" pattern. We know if we give this pattern the input:I am sad.it should respond with: I AM SORRY TO HEAR YOU ARE SAD.So let's test this by doing the following:
![]() ![]() ![]() Getting ready to write more testsYou may think that the code we wrote for testing the response to "I am sad." seems like a lot of work, especially since we'd have to repeat this code in order to test every decomposition rule in every pattern. In reality, every test we write is virtually identical. The only difference between each test is the user input passed to GetResponse() and the response we're checking for. To reduce the effort of writing tests, we'll create a helper class Test that will do the actual testing. ElizaTest will then simply use Test to specify what needs to be tested and will call its Test.Run() method to run the test. This will allow us to express our tests in a concise form, as shown below.![]()
Think how you would construct the Test class. When finished, compare your solution
to the code below.
![]() Improving the testing frameworkNow that we have a Test class, we could simply instantiate and run it for every decomposition rule we want to test. But that would cause ElizaTest's Main() method to grow to an unwieldy size. Instead, we'll create a new TestPattern class responsible for testing a specific pattern. TestPattern in turn will create and run instances of Test for every decomposition rule in the pattern. TestPattern will be an abstract class, which will require its pattern specific derived class to construct its Test instances. The first pattern we'll test will be the "AM" pattern, so AmPatternTest will be the first subclass of PatternTest. Test and PatternTest constitute our testing framework. So we'll locate them in a "TestFramework" folder within the ElizaTest project. Pattern specific classes (like AmPatternTest) that derive from PatternTest will be located in the "PatternTests" folder.![]()
Always write tests by examining the program's REQUIREMENTS, not its code.
Remember, the purpose of a test is to ensure the code meets the program's
requirements.
Our first pattern testHere's what the test for the "AM" pattern looks like:![]() ![]()
Want to sleep well at night? Ensure you have tests in place for all
your app's functionality. That way, if you (or someone else) modifies
the app's code, running your tests will ensure that the changes didn't break
anything, or if they did, you'll at least know where to look!
Testable Eliza!Eliza is finally testable! Here's what the ElizaTest project looks like after creating tests for every pattern. Notice that we moved complex and format free pattern tests to separate folders to keep things organized.![]() ![]() Next stepsWe're now ready to code all the remaining patterns, including those that utilize synonyms. Our version of Eliza is getting close to becoming what Joseph Weizenbaum created in 1965. |