Skip to main content
Engineering LibreTexts

9.4: SUnit by Example

  • Page ID
    39622
    \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \) \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)\(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\) \(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\)\(\newcommand{\AA}{\unicode[.8,0]{x212B}}\)

    Before going into the details of SUnit, we will show a step by step example. We use an example that tests the class Set. Try entering the code as we go along.

    Step 1: Create the test class

    First you should create a new subclass of TestCase called MyExampleSetTest. Add two instance variables so that your new class looks like this:

    TestCase subclass: #MyExampleSetTest
        instanceVariableNames: 'full empty'
        classVariableNames: ''
        package: 'MySetTest'
    

    We will use the class MyExampleSetTest to group all the tests related to the class Set. It defines the context in which the tests will run. Here the context is described by the two instance variables full and empty that we will use to represent a full and an empty set.

    The name of the class is not critical, but by convention it should end in Test. If you define a class called Pattern and call the corresponding test class PatternTest, the two classes will be alphabetized together in the browser (assuming that they are in the same package). It is critical that your class is a subclass of TestCase.

    Step 2: Initialize the test context

    The message TestCase >> setUp defines the context in which the tests will run, a bit like an initialize method. setUp is invoked before the execution of each test method defined in the test class.

    Define the setUp method as follows, to initialize the empty variable to refer to an empty set and the full variable to refer to a set containing two elements.

    MyExampleSetTest >> setUp
        empty := Set new.
        full := Set with: 5 with: 6
    

    In testing jargon the context is called the fixture for the test.

    Step 3: write some test methods

    Let’s create some tests by defining some methods in the class MyExampleSetTest. Each method represents one test. The names of the methods should start with the string 'test' so that SUnit will collect them into test suites. Test methods take no arguments.

    Define the following test methods. The first test, named testIncludes, tests the includes: method of Set. The test says that sending the message includes: 5 to a set containing 5 should return true. Clearly, this test relies on the fact that the setUp method has already run.

    MyExampleSetTest >> testIncludes
        self assert: (full includes: 5).
        self assert: (full includes: 6)
    

    The second test, named testOccurrences, verifies that the number of occurrences of 5 in full set is equal to one, even if we add another element 5 to the set.

    MyExampleSetTest >> testOccurrences
        self assert: (empty occurrencesOf: 0) = 0.
        self assert: (full occurrencesOf: 5) = 1.
        full add: 5.
        self assert: (full occurrencesOf: 5) = 1
    

    Finally, we test that the set no longer contains the element 5 after we have removed it.

    MyExampleSetTest >> testRemove
        full remove: 5.
        self assert: (full includes: 6).
        self deny: (full includes: 5)
    

    Note the use of the method TestCase >> deny: to assert something that should not be true. aTest deny: anExpression is equivalent to aTest assert: anExpression not, but is much more readable.

    Step 4: Run the tests

    The easiest way to run the tests is directly from the browser. Simply click on the icon of the class name, or on an individual test method, and select Run tests (t) or press the icon. The test methods will be flagged green or red, depending on whether they pass or not (as shown in Figure \(\PageIndex{1}\)).

    Running SUnit tests from the System Browser.
    Figure \(\PageIndex{1}\): Running SUnit tests from the System Browser.

    You can also select sets of test suites to run, and obtain a more detailed log of the results using the SUnit Test Runner, which you can open by selecting World > Test Runner.

    The Test Runner, shown in Figure \(\PageIndex{2}\), is designed to make it easy to execute groups of tests.

    Running SUnit tests using the TestRunner.
    Figure \(\PageIndex{2}\): Running SUnit tests using the TestRunner.

    The left-most pane lists all of the packages that contain test classes (i.e., subclasses of TestCase). When some of these packages are selected, the test classes that they contain appear in the pane to the right. Abstract classes are italicized, and the test class hierarchy is shown by indentation, so subclasses of ClassTestCase are indented more than subclasses of TestCase. ClassTestCase is a class offering utilities methods to compute test coverage.

    Open a Test Runner, select the package MySetTest, and click the Run Selected button.

    You can also run a single test (and print the usual pass/fail result summary) by executing a Print it on the following code: MyExampleSetTest run: #testRemove.

    Some people include an executable comment in their test methods that allows running a test method with a Do it from the browser, as shown below.

    MyExampleSetTest >> testRemove
        "self run: #testRemove"
        full remove: 5.
        self assert: (full includes: 6).
        self deny: (full includes: 5)
    

    Introduce a bug in MyExampleSetTest >> testRemove and run the tests again. For example, change 6 to 7, as in:

    MyExampleSetTest >> testRemove
        full remove: 5.
        self assert: (full includes: 7).
        self deny: (full includes: 5)
    

    The tests that did not pass (if any) are listed in the right-hand panes of the Test Runner. If you want to debug one, to see why it failed, just click on the name. Alternatively, you can execute one of the following expressions:

    (MyExampleSetTest selector: #testRemove) debug
    MyExampleSetTest debug: #testRemove
    

    Step 5: Interpret the results

    The method assert: is defined in the class TestAsserter. This is a superclass of TestCase and therefore all other TestCase subclasses and is responsible for all kind of test result assertions. The assert: method expects a boolean argument, usually the value of a tested expression. When the argument is true, the test passes; when the argument is false, the test fails.

    There are actually three possible outcomes of a test: passing, failing, and raising an error.

    • Passing. The outcome that we hope for is that all of the assertions in the test are true, in which case the test passes. In the test runner, when all of the tests pass, the bar at the top turns green. However, there are two other ways that running a test can go wrong.
    • Failing. The obvious way is that one of the assertions can be false, causing the test to fail.
    • Error. The other possibility is that some kind of error occurs during the execution of the test, such as a message not understood error or an index out of bounds error. If an error occurs, the assertions in the test method may not have been executed at all, so we can’t say that the test has failed; nevertheless, something is clearly wrong!

    In the test runner, failing tests cause the bar at the top to turn yellow, and are listed in the middle pane on the right, whereas tests with errors cause the bar to turn red, and are listed in the bottom pane on the right.

    Modify your tests to provoke both errors and failures.


    This page titled 9.4: SUnit by Example is shared under a CC BY-SA 3.0 license and was authored, remixed, and/or curated by via source content that was edited to the style and standards of the LibreTexts platform; a detailed edit history is available upon request.