Simple Smalltalk Testing
Simple Smalltalk Testing
Unittasting
I recommend that developers write their own unit tests, one per
class. The framework supports the writing of suites of tests,
Integration
tasting
KENT BECK
testing 1 recommend that an independent tester write integration tests.
Where should the integration tests go? The recent movement
of user-interface frameworks to better facilitate programmatic
access provides one answer-drive the user interface, but do it
Y
ou can’t argue with inspiration (or deadlines). I started with the tests. In VisualWorks (the dialect used in the imple-
to write the final column in the sequence about using mentation below), you can open an ApplicationModel and
patterns for design, but what came out was this. lt begin stuffing values into its ValueHolders, causing all sorts of
describes some work I have been doing with a framework that havoc, with very little trouble.
takes the tedium out of vvriting tests. 1’11get back to the pat-
tern sti in the next issue. Running tasts
SmsIltalk has suffered because it lacks a testing culture. This One final bit of philosophy. It is tempting to set up a bunch of
column describes a simple testing strategy and a framework to test data, then run a bunch of tests, then clean up. In my experi-
support
.. it. The testing strate~—. and framework are not intended ence, thk procedure always causes more problems hat it is
to be complete solutions, but, rather, are intended to be starting worth. Tests end up interacting with one another, and a failure
points from which industrial strength tools and procedures can in one test can prevent subsequent tests from running. The test-
be constructed. ing ilamework makes it easy to set up a common set of test
The article is divided into four sections: data, but the data will be created and thrown away for each test.
- Philomphy. Describes the phdosophy of writing and running The potential performance problems with this approach should-
tests embodied by the framework. Read this section for gen- n’t be a big deal, because suites of tests can run unobserved.
eral background.
● Framework. A literate program version of the testing frame- FRAMEWORK
work. Read this for in-depth knowledge of how the frame- The smallest unit of testing is the TestCase. When a TestCase
work operates. runs, it sets up its test data, runs a test method, then discards
● Example. An example of using the testing framework to test the test data. Because many cases may want to share the same
part of the methods in Set. test data, TestCase chooses which method to run with the
● Cookbook.A simple cookbook for writing yow own tests. instance variable selector, which will be pefiormed to run the
test method.
PHILOSOPHY class:TestCase
The most radical philosophy espoused here is a rejection of superclass:Object
user-interface-based tests. In my experience, tests based on user instance variables: selector
interface scripts are too brittle to be useful. Testers spend more classvariable: FailedChecMignal
time keeping the tests up to date and tracking down false fail- TestCases are always created with a selector. The class method
ures and false successes than they do writing new tests. selector: ensures thk.
My solution is to write the tests (and check results) in TestCaseclass>>selecto~asyrrrbol
Smslltalk. Although thk approach has the disadvantage that ‘self new setselecto~ a$nnbol
your testers need to be able to write simple Smalkslk programs, TestCase>>setSelectora$nnbol
the resulting tests are much more stable. selector:= a$nrrbol
The simplest way to run a TestCase is just to send it the message
Failurss and errors run. run invokes the set up code, performs the selector, then
The framework distinguishes between failures and errors. A runs the tear-down code. Notice that the tear-down code is run
failure is an anticipated problem. When you write tests, you regardless of whether there is an error in performing the test.
TestCase>>run
self setUp.
[selfperforrnTest]
vahmNorvOrOnUnwindDo:
[selftearDown]!
October 1994 17
errors add: (Arraywith: aTestCasewitlu aSh’ing)
TestResul&>faihuc aShing im aTestCase
failures add (Arraywith aTestCasewith: XYzirrg)
The error case gets invoked if there is ever an uncaught error
(for example, message not understood) in the testing method.
How do the fadures get invoked? TestCase provides two meth-
ods that simpliij checking for fdure. The first, should: aBIoek, SetTestCase r
selector #testiHegal
u
signala a failure if the evaluation of aBlock returns false. The \
second, shouldnt: aBlock, does just the opposite. full
should:aBlock empty
tilock value ifTalse:[self failedCheckSignalraise]
shouldrmfllOCk
aBlockvalue Whua [self failedCheckSignalraise]
Testing methods wiU likely run some code, then check the
==7
startTime #(26 August 19942:09:00 am)
results inside should: and shoukink blocks.
stopTime #(26 August 19942:09:01 am)
EKAMPLE
Okay that’s how it worka, but how do you use it? Here’s a short
testName
I
failuresOrderedCollection ()
example that tests a few of the messages supported by Sets. errorsOrderedCollection ()
First we subclass TestCase, because we’ll always want a couple
of interesting Sets around to play with:
Class:SetTestCase
Figurs 1.
superclass TestCase
instancevariables:emptyfull
Now we need to initialize these variables, so we subclass setUp. functionfllty in Set. Writing tests for all the public methods in
SetTestCase>>setUp Set is a daunting task. However, as Hal Hddebrand told me
empty:= Set new. after using an e~lier version of this i%rnework, “If the underly-
full:= Set viiti #abc rvith: 5 ing objects don’t work, notlsing else matters. You have to write
Now we need a testing method. Let’s test to see if adding an the tests to make sure everything is working.”
element to a Set really works:
SetTestCaae>>testAdd COOKBOOK
empty add: 5. Here are simple steps you can follow to write your own tests:
self should: [emptyincludes: 5] 1. Scope the tests. Decide whether you want to test one object
Now we can run a test case by evaluating: or several cooperating objects. Subclass TestCase, prei%ring
(SetTestCaseselector #testAdd) run. the name of your test scope.
Here’s a case that uses shouldnt:. It reads ‘after removing 5 2. Create test ilxture. Find a few configurations of your objects
from W, full should include #abc and it shouldn’t include 5.” that will exercise the code you want to test. Add an instance
SetTestCase>>testRemove variable to your TestCase subclass for each configuration.
full remove: 5. Override setUp to create the configurations.
self should [fullinchrdex#abc]. 3. Write the test methods. Write a method for each distinct
selfshouldnk [fullincludes:5] test you want to perform. Use should and shouldnt wher-
Here’s one that makes sure an error is signaled if you try to do ever you can check for comect or incorrect results. As you
keyed access: write each method, test it by creating an instance of your
SetTestCase>*stIllegal TestCase subclass and sending it nm.
selfshould [selferrorSignal 4. Create the suite. Write a method in one of the classes you
handle: [:ex I true] do: [empty ak 5. false]] are testing that collects all of the TestCases into a TestSuite
Now we can put together a TestSuite. and returns it.
I suite I
suite:= TestSuite named: ‘SetTesta’. CONCLUSION
suite addTestCase:(SetTestCaseselecto~ #testAdd). This column has presented the philosophy and implementation
suite addTestCase:(SetTestCaseselecto~ #testRemove). of a simple testing stiate~ for Smalltalk. The strate~ has the
suite addTestCase:(SetTestCaseselectoc #testIllegal). advantages that it is simple, lightweight, and produces tests that
‘suite are stable. It is not complete or perfect, but it’s a whole lot better
Figure 1 showa an Object Explorer picture of the suite and of than no programmatic tests at all. As ahvays, if you have com-
the TestResult we get back when we run it. ments, plesse pass them on to me at
The test methods shown above only cover a fraction of the 70761 .1216@compuserve.com. q