CPS506 - Comparative Programming Languages - Winter 2022

Lab 3 - Test-Driven-Design in Smalltalk

Objectives

  • Become familar the test framework and TDD in Smaltalk

Introduction

Test-Driven-Design is one of the more important tools for developing correct and reliable software to come along in years. Smalltalk is at the leading edge of this trend. Unit testing is a way to incrementally build an application without regressions on previously working parts. SUnit is the Smalltalk framework (and has been emulated in JUnit for Java, PyUnit or unittest for Python, NUnit for C#, ExUnit for Elixir, HUnit for Haskell, built into Rust, and many other frameworks for most common programming languages.

Problem Description

We're going to implement a simple stack in Smalltalk. It is going to have typical operations for stacks, as well as some special ones:

  1. push: value - pushes the value on top of the stack
  2. pop - pops the top value of the stack and returns it
  3. top - returns the top value from the stack without any side-effect to the stack
  4. isEmpty - returns true if the stack is empty, false otherwise
  5. dup - push a copy of the top element onto the stack
  6. swap - exchange the top two elements on the stack
  7. add - add the top two values on the stack, replacing them with the result; similarly for mult
  8. sub - subtract the top value on the stack from the value below it, replacing them with the result; similarly for div
  9. + value - add the immediate value to the top of the stack, leaving the result there; similarly for *, -, and / where the immediate value is the right-hand argument
  10. ~- value - subtract the top of the stack from the immediate value, leaving the result there; similarly for ~/; these are like the previous ones, but the immediate value is the left-hand argument

Tests

  1. Create a package CPS506 if you haven't yet
  2. Create the class Lab3Test:
    TestCase subclass: #Lab3Test
    	instanceVariableNames: ''
    	classVariableNames: ''
            package: 'CPS506'
  3. Create the method testBasic in the class:
    testStack
            stack := Lab3Stack new.
            self assert: stack isEmpty.
    	stack push: 42.
    	self assert: stack top equals: 42.
    	stack push: 17.
    	self assert: stack top equals: 17.
    	stack pop.
    	self assert: stack top equals: 42.
    	stack pop.
    	self assert: stack isEmpty
  4. When you try to save it, you will see some error requiring you to define the Lab3Stack class (the default is fine), and where to put the stack variable (may as well make it an instance variable).
  5. When you have successfully saved it, you will see a little grey circle in front of the test name in the top-right panel (method list). You will see that there is another circle in front of the class name in the class list (top-2nd panel). Click that circle and it will run all the tests and give you a red pop-up notification (the notification fades in a few seconds if your mouse isn't over it).
  6. Click the circle in front of the test method name and it will run just that test, giving you a debug window if anything fails. From here you can create missing methods, single step code, inspect values of expressions (highlight them, then cmd-i or ctrl-i). Work through it until you get a green result. Clicking on the circle in front of the class will re-run all the tests, and should show green.
  7. Create a new method testStack to test the stack manipulation methods. Work through it, defining methods, until it's green too. Click on the circle in front of the class again to have it run all the tests, and verify you didn't break something else while fixing this one.
  8. Create a new method testArithmetic to test the arithmetic operations, and work to get everything green.