How to Test
Before
Submitting to
Bender
Overview
Successfully passing tests
run by a robot like Bender requires a systematic and thorough approach to
testing. This page describes such an
approach. It assumes you're testing on Unix, which you must do prior to Bender submission to be
sure everything is correct.
Step 0 – What not to do
First step is what not to do. Do not..
A.
Run tests just on a local computer, and hope that they'll run on Unix also. Bugs may
be hidden on your local machine, and show up on Unix,
especially if you're using C.
B.
Check for accuracy by "eyeballing" output from your program to see if
it looks right. If you aren't running
"diff" (see below) you will
miss errors.
C.
Rough out a test or two and call it good enough. Testing is a thoroughgoing discpline. See here for more information.
Step 1 – Build your test cases
Write a series of test files,
using the approach and philosophy described here. Name them in orderly fashion, e.g. test1.in,
test2.in, etc. You may also use any test
cases I supply, but note that for many assignments (I'll tell you which) Bender
uses additional tests that are not publicized.
You need to write more tests of your own.
Make your test cases
thorough. If you come to me asking why
Bender is bouncing you when you think your program is correct, the first question
I will ask is "Please show me your test cases and your script for running
them." (See below.) The following
are unacceptable answers to this request:
"I don't have actual
test files but I checked it really carefully."
"I looked over the outputs
and it's right."
"I ran them on my
Windows machine so it should be fine."
"I just used the test
cases you gave." (Unless the assignment permit
this)
and the ever-popular
"Test
cases???"
Step 2 – Verify your test cases
A. Run my sample executable on your test files. If the executable accepts input from the
keyboard, redirect from the file, and save the ouput
(which would otherwise appear on screen) thus:
[my executable] <
test1.in > clint1.out
B. Run your executable to create
your version of the output:
[your executable] < test1.in > my1.out
C. Compare the two using "diff" with the "-bw" option which makes diff a
little more tolerant about blank lines and spaces. (Bender runs it this way.)
diff -bw clint1.out my1.out
Any
output at all from diff is a bad thing.
No output means you have a perfect match. Diff shows lines that differ between your
file and mine. Lines in the first file
(mine in the example above) are marked with a preceding
"<" and those in the second file are marked with a preceding
">".
Step 3 – Make the tests easy to run
You end up running a lot of
commands to do testing, even with the prewritten input files like
test1.in. You have to run your program,
run mine, save outputs, do a diff, and repeat for as many test cases as you
have. Any time you find yourself repeating
the same Unix commands over and over, it's time for a shell script. A shell script is a text file that contains a
program. You write it using vi, just like your C or Java program. But, the commands in the shell script aren't
C or Java; they're Unix
commands. You type into the shell
script file, using vi, exactly the set of Unix
commands you want to run, and save it.
For instance, just as an example, you might fill a shell script file called
"runtests" with these 4 commands.
echo Doing test1
myexec <
test1.in > my1.out
clintsExec <
test1.in > clints1.out
diff -bw my1.out clints1.out
Once you've saved "runtests" as a file containing the 4 Unix commands, you need one more step:
chmod 700 runtests
This makes the runtests text file runnable like
a program such as a.out. You
have now created a shell script. You may
run the shell script as a command in its own right, just as though it were an
executable:
runtests
All the Unix
commands in the shell script will be performed in sequence. It's like a little Unix
"player piano". You just run
the script file with that one command and all those commands you put into the runtests file get run in order (including the
"echo", which we'll talk about in a moment). You can watch all the commands go by on the
screen, with your hands off the keyboard.
Any output that results from the commands (especially diff) will show on
the screen, for you to diagnose. In
effect, you now have your own small Bender, though Bender himself is actually a
pumped-up 241-line shell script.
You'll probably want to do
several different input files in your script, with diffs
on each output. In that case, it's easy
to get lost in the output, not knowing which diff command in the script
produced which output line. That's where
the "echo" comes in. *All*
this command does is print back whatever you gave for arguments,
mindlessly. So you can write:
echo Mary had a little lamb
(Try it!) And the command
will print "Mary had a little lamb". You use this like a printf in scripts, to tell what part of the script is
running. When the script reaches the
echo command, it just prints on the screen whatever the echo says to print, and you can tell where in the script you are by
seeing where the echo prints occur.