Getting Started with tcltest

The Problem

I want to use tcltest to unit test my code, but don’t know how to start.

The Solution

This tutorial will guide you through a step-by-step process on how to get started with tcltest

Installation

Installation is in in the scope of this tutorial, I assume that you have Tcl 8.4 or 8.5 installed. Chances are, you have tcltest package installed as well. To check, type the following command to your terminal:

tclsh
package require tcltest
exit

If you don’t see any error messages, then you are set. Otherwise, please install Tcl 8.4 or later, and tcltest.

Your Software under Test

In this tutorial, I assume the software under test (SUT) is a set of functions in a file called sum.tcl:

proc sum {a b} {
    expr {$a + $b}
}

Create a “main” Test Script

The first step is to create a main script. This script will drive all the tests in the current directory. I name this file all.tcl:

package require tcltest
namespace import ::tcltest::*
runAllTests

Next, test this main script:

tclsh all.tcl

The output should look similar to this:

Tests running in interp:  /usr/bin/tclsh
Tests located in:  /Users/haiv/src/tcl/tcltest_getting_started
Tests running in:  /Users/haiv/src/tcl/tcltest_getting_started
Temporary files stored in /Users/haiv/src/tcl/tcltest_getting_started
Test files run in separate interpreters
Running tests that match:  *
Skipping test files that match:  l.*.test
Only running test files that match:  *.test
Tests began at Mon Mar 28 09:37:40 PDT 2011
Error:  No test files remain after applying your match and skip patterns!

Tests ended at Mon Mar 28 09:37:40 PDT 2011
all.tcl:	Total	0	Passed	0	Skipped	0	Failed	0
Sourced 0 Test Files.

Note the next-to-last line of the output: it said we have 0 tests, so writing a test is the next task.

Writing the First Test Module

In this tutorial, I will write one test file (module) per function. However, you can organize your tests in any way you want. Let’s create the first test module to test the sum function and call it sum.test. Note that by default, tcltest will look for files with .test extension and assume them to be a test module. The contents of sum.test look like this:

# sum.test

package require tcltest
namespace import ::tcltest::*

# Software under test
source sum.tcl

test sum_addTwoZerosExpectZero {
    Test: [sum 0 0] == 0
} -body {
    sum 0 0
} -result 0

test sum_addTwoPositiveNumbers {} -body {
    sum 4 9
} -result 13

test sum_addPositiveToNegative {} -body {
    sum -95 72
} -result -23

cleanupTests

Explanation:

  • Line 3,4: Use the tcltest package. The namespace import line allows you to skip the name space. For example, you can use test instead of tcltest::test
  • Line 7: Includes the software under test into your test module.
  • Lines 9-13: Our first test case starts with the ‘test’ command. The first argument is the name of the test, followed by the test description (line 10), the test body (line 12). We will discuss more about test case in the next section.
  • Lines 15-21: Defines two more test cases. For the sake of brevity, I ommit the test descriptions
  • Line 23: This line is required to tally all the test results for this module.

About a Test Case

In unit testing, each test case should be small, concise, and only test 1 aspect of the software. That way, when a test failed, we know exactly what is failed and hopefully, why it faied and how to fix it. The test description follows the test name. I recommend not to leave the description empty, unless you think the test name is descriptive enough.

Running the Tests

Now that we have our first test case written, it is time to run it. From the terminal issue the following command:

tclsh all.tcl

Output:

Tests running in interp:  /usr/bin/tclsh
Tests located in:  /Users/haiv/src/tcl/tcltest_getting_started
Tests running in:  /Users/haiv/src/tcl/tcltest_getting_started
Temporary files stored in /Users/haiv/src/tcl/tcltest_getting_started
Test files run in separate interpreters
Running tests that match:  *
Skipping test files that match:  l.*.test
Only running test files that match:  *.test
Tests began at Mon Mar 28 15:10:03 PDT 2011
sum.test

Tests ended at Mon Mar 28 15:10:03 PDT 2011
all.tcl:	Total	3	Passed	3	Skipped	0	Failed	0
Sourced 1 Test Files.

Note that now the sumary line shows 3 tests and it was passing. You are now free to add more test cases to the sum.test module or create a new module. That concludes my tutorial. In the next installment, I am going to talk about organizing the tests and adding more test modules to the mix.

8 thoughts on “Getting Started with tcltest

  1. Pingback: tcltest Part 2 – Multi-Module Test Suite « Hai’s Blog

  2. Pingback: tcltest Part 3 – Include and Exclude Tests « Hai’s Blog

  3. Zbigniew Diaczyszyn

    Hi,

    just googled for “runAllTests” and encountered your blog. I am just a Tcl/Tk aficionado but perhaps my remark can be useful:

    Recursive use of runAllTests

    Suppose you have a test directory unit-tests/ with subdirectories module1/ and module2/ and you want to create a test suite.

    If you put the following file all.tcl into each of your test directories then testing will be recursive.

    The command runAlltests in the master script all.tcl which is located in unit-tests/ will perform all tests (per default look for *.test files) and then scan the subdirectories for the file all.tcl. And so on.

    ————— all.tcl ——————-

    package require tcltest 2.2

    # default search path is the actual working directory
    tcltest::configure -testdir [file dirname [file normalize [info script]]]

    eval tcltest::configure $argv

    # If a file named all.tcl is found in a subdirectory of the scanned
    # test directory, it will be sourced in the caller’s context.

    tcltest::runAllTests
    ———————— eof ——————————-

    And perhaps this can be useful, too:

    if you enter on the command line:

    tkcon myapplication.tcl

    you are “inside” your application and you can interactively submit commands to your application. For examle:

    source all.tcl

    So it is possible to test even a Tk based application.

  4. Hai Post author

    Zbigniew Diaczyszyn: This is excellent information. I will make your suggestion a separate installment.

  5. Pingback: GUIDE: tclunit/TDD for Tcl, usage and examples. | Automate your world

  6. Pawel

    Hello
    I have one qustion, because i made a bat file with “tclsh all.tcl” line and i would like to have some value returned by this bat file depends on that if there was any errors inside the scripts or not. Right now after “tclsh all.tcl” call errorlevel in windows is always 0 even if there are some errors in tests

  7. Hai Post author

    @Pawel: The trick is to determine if any of the tests failed and returns 1. It took me a while to find a solution, see my part 9 of the tcltest series. Thank you for asking an excellent question.

  8. Pingback: Wyzwanie Women in Technology- spotkanie z cyklu Girls 4 Girls we Wrocławiu | Women in Technology

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s