Unit Testing with SUnit

Kent Beck wrote SUnit in Smalltalk (described in his 1994 paper *Simple Smalltalk Testing: With Patterns*); it was ported to Java as JUnit with Erich Gamma, spawning the entire xUnit family.

25.1 History

Kent Beck wrote SUnit in Smalltalk (described in his 1994 paper *Simple Smalltalk Testing: With Patterns*); it was ported to Java as JUnit with Erich Gamma, spawning the entire xUnit family.

25.2 A test class

Test methods start with test and take no arguments.

setUp runs before each test, tearDown after each test (even on failure).

Each test runs on a fresh instance of the test class.

TestCase << #BankAccountTest
    slots: { #account };
    package: 'Bank-Tests'

BankAccountTest >> setUp
    super setUp.
    account := BankAccount owner: 'Ada' balance: 100

BankAccountTest >> testDeposit
    account deposit: 50.
    self assert: account balance equals: 150

BankAccountTest >> testWithdraw
    account withdraw: 30.
    self assert: account balance equals: 70

BankAccountTest >> testWithdrawTooMuchRaisesError
    self should: [ account withdraw: 1000 ] raise: InsufficientFunds.
    self assert: account balance equals: 100

BankAccountTest >> testNegativeDepositIsRejected
    self should: [ account deposit: -5 ] raise: Error

BankAccountTest >> testPrintString
    self assert: (account printString includesSubstring: 'Ada')

25.3 Assertions

assert: aBoolean Fails if false deny: aBoolean assert: actual equals: expected Equality with a helpful failure message deny: actual equals: unexpected assert: aBoolean description: 'msg'

should: aBlock raise: anExceptionClass Block must signal the exception

shouldnt: aBlock raise: anExceptionClass Block must not signal it

should: aBlock raise: anException withExceptionDo: [:ex |...] Further checks on the exception

assertCollection: a hasSameElements: b Same elements, order ignored

assertEmpty: aCollection / denyEmpty: fail / fail: 'msg' skip / skip: 'reason'

25.4 Running tests

In the browser, click the round icon next to a test method, class, or package (green = pass, yellow = failure, red = error).

*Tools → Test Runner* or DrTests for suites, coverage, and profiling.

Command line: ./pharo Pharo.image test "Bank-Tests" (the test command-line handler runs packages matching a pattern and exits).

BankAccountTest suite run.                     "→ a TestResult with a summary like '5 ran, 5 passed'"
(BankAccountTest selector: #testDeposit) run.
BankAccountTest buildSuite run printString.

25.5 Failures vs errors

Failure (yellow): an assertion was false.

Error (red): an unexpected exception occurred.

Click a failing test to open the debugger at the failing assertion — then fix the code right there.

25.6 More features

expectedFailures (instance side) lists known-failing test selectors; class-side isAbstract and shouldInheritSelectors control abstract test classes and inherited tests.

TestResource subclasses share expensive setup across tests (resources).

ParametrizedTestCase (Pharo) runs the same tests over a matrix of parameters.

Mocking libraries: Mocketry, BabyMock2; but in Smalltalk, simple hand-written fakes are usually enough thanks to duck typing.

Test coverage: DrTests' coverage plugin.