We tested our new code manually. There's a tool built in to Squeak called SUnit which allows for repeatable test execution. If we add test code to SUnit to check our new filename copy method we could assure that any time someone makes changes to the FileList class in the future, if they run SUnit, they will know if they did something causing our code to break.
In the world of eXtreme Programming (XP) the rule is that you write the SUnit test case code before you implement your model or solution code. The idea is that by thinking about how the test should work you will better understand how the code should be designed. We didn't do that in this case however. But we will later in the example.
The first check we should make is to actually exercise SUnit. The idea is that the running of all known test cases should not produce any test failures. Once we are certain we can introduce our new test. In general, we would actually run SUnit tests before we introduce a single line of code in FileList, and verify that all tests pass. Then, if there are sufficient tests for FileList, when we run SUnit again after we add code we might expect something to break in a test. That's assuming the changes we make would be caught by an existing test case. Regardless, let's take a moment and review how to run SUnit tests in Squeak.
In Squeak 3.5 you launch SUnit by opening the Test Runner from the "open..." menu.
The next check we should make is to see if there already is a FileList test class in SUnit. There is! Again, back when the tutorial was written to use Squeak 3.2 there was no pre-existing FileList test case. If there had not been, we would have made a new subclass of TestCase and continued.
Let's add a test for our new method to the test case. Using a standard class Browser we perform a "find class..." on FileListTest. Choose the "test" method protocol to review the existing test methods.
I'd like to exercise FileList and validate that the original "copy name to clipboard" menu operation and the new "copy just file name to clipboard" menu operation work as expected. Since we cannot expect the environment SUnit is running in to have any specific file we can use for testing, we'll have to create one.
After we create the temporary file we will use just for the tests, we'll perform some operations on it, verify expected results, and then delete the file.
I wrote a few methods to support our intent to test this way. Both these two methods shown below are included in the method cateogry "private" on our test class. Here are the two new methods:
The #createTempFile method answers an Association containing the location and actual file name of the temporary file we create. Since we will be using a GUI list and menu to test our new code we'll have to write a little bit of support code to make it easy to interact with the FileList GUI.
^ 'test file contents'
| dir time fname fstream |
dir := FileDirectory default.
time := Time now.
fname := time hhmm24 , time seconds printString , '.tmp'.
(dir fileExists: fname)
ifTrue: [dir deleteFileNamed: fname].
fstream := dir forceNewFileNamed: fname.
fstream nextPutAll: self tempFileContents.
^ dir -> fname
Now we can create the test code. SUnit will exercise all methods in subclasses of TestCase that begin with "test" in the selector name. Here's the test code. I put it in the "test" method category.
^ ((gui allMorphs
select: [:m | m isKindOf: PluggableListMorph])
select: [:m | m getListSelector = #fileList]) first
There's a bunch of little "tricks" going on in here. First we got lucky because the FileList #openAsMorph class method answers a SystemWindow but doesn't actually open it. So we can use that window morph and ask it questions about it's submorphs.
| gui assoc dir fname entry index listMorph string |
ifFalse: [^ nil].
assoc := self createTempFile.
dir := assoc key.
fname := assoc value.
gui := FileList openAsMorph.
"Since we just opened up the FileList we can assume it's directory
is the same as ours."
entry := gui model fileList
detect: [:each | each includesSubString: fname]
index := gui model fileList indexOf: entry.
listMorph := self fileListMorph: gui.
listMorph selectionIndex: index.
gui model fileListIndex: index.
"Now that we faked the selection of our test file, ask our FileList
to copy the name."
gui model copyName.
string := Clipboard clipboardText string.
self assert: string = (dir fullNameFor: fname).
gui model copyJustFileName.
string := Clipboard clipboardText string.
self assert: string = fname.
"Done with the file."
dir deleteFileNamed: fname.
Also, once we had all the hooks in place to test the new #copyJustFileName method we wrote, we may as well test the existing one that answered the full path: #copyName also. The #assert: methods will generate an error that SUnit will log if the condition we assert is not true.
Run the SUnit tests again after adding this method.
Close The Test Runner.
Go on to Second Enhancement to File List.
Back to the beginning of this example.stacy sanches nude