Lab 01: Introduction to C++ and Testing
Due: by the end of your lab period
Goal
In your first laboratory assignment, you will use a simple pre-written Calculator class and driver
code in C++ to learn how to write and test a simple C++ program.
You will then implement test cases for the Calculator class by using the CxxTest framework.
Learning Objectives
Familiarity with Eclipse C++ projects
Exposure to basic C++ syntax
Exposure to simple CxxTest unit tests
First, a Word About Pair Programming
Pair programming is a relatively new idea to help increase productivity and quality in the
software that you write. In computer science lab classes, there is suggestive evidence that pair
programming increases grades (even on exams and other individual work), decreases student
frustration, and increases the success rate of members of underrepresented groups. In the
laboratories this semester, you will be paired each week with a different person and be required
to participate in paired programming techniques as instructed by your teaching assistant.
This week, we're only going to introduce the notion of working together in these lab exercises.
Most students are probably unfamiliar with pair programming. When working in a pair, one of
you will be the driver--the student typing at the computer or writing down designs/notes. The
other student will be the navigator--observing the work of the driver, looking for software
defects (syntax errors, logic errors, etc.), asking questions about the design as it develops, and
otherwise communicating thoughts to the driver.
There are four parts to this lab; one of you will be the driver for parts I and III, and the
navigator for parts II and IV. Once paired with another student, decide who will be the driver
during part I and then switch roles during the succeeding parts. Finally, for this lab (and all
others unless we tell you otherwise), you should know that the driver is the only member of the
pair who is allowed to touch the keyboard. The navigator is allowed to point out errors, and
make comments. This is encouraged behavior! However the navigator is not permitted to take or
otherwise obtain the keyboard from the driver and begin to type into the computer!
Part I: Creating a Simple C++ Class
In Part I of this lab assignment, you will create a new Eclipse C++ project with CxxTest enabled,
copy the code of an existing class that we provide into the project, and then add some unit tests
to verify that the class works as intended.
1. Create a new Eclipse project
a. Decide which of you will be the driver for Part I. The driver should log in (if
you're using a lab machine). For the remaining instructions in Part I, the driver
should do all the typing/mousing. The driver should feel free to ask for advice or
bounce ideas off the navigator, and the navigator should look out for errors in
what the driver is typing.
b. Start Eclipse on your machine. Create a new project in your workspace; these
steps differ depending on which version of Eclipse you are running:
If you're using the VT Eclipse bundle, select File / New / Project… from the
menu. Expand the C++ branch of the tree if necessary and choose "C++
Project" and click "Next". Enter "Calculator" as the project name, then
expand the "Executable" branch under "Project types:" and select "Empty
Project" (without CxxTest). Then click "Finish".
If you're using the Eclipse for C/C++ Developers distribution, then select
File / New / C++ Project… from the menu. Enter "Calculator" as the
project name, then expand the "Executable" branch under "Project types:"
and select "Empty Project". Then click "Finish".
2. Create the Calculator class
a) We will be creating a simple "Calculator" class. This class holds a field that
represents a current integer value and methods that allow the user to perform
basic arithmetic operations on that value. To create the class, right-click on the
"Calculator" project in the "C/C++ Projects" view and choosing New / Class…
from the menu. Enter "Calculator" as the name of the class and click "Finish."
This will create two new files in your project — a header file Calculator.h and
an implementation file Calculator.cpp. Note the difference from the Java
approach — in C++, the header file typically contains only the list of fields and
methods that the class contains, and the implementation file contains the actual
code that defines those methods. (It is possible to include method code in the
header file, but that is generally considered bad style for C++ classes.)
The class that is generated will contain empty stubs for the class constructor and
destructor. The header file also contains lines beginning with # characters at the
beginning and end of the file. In a nutshell, these specific lines are "inclusion
guards." These are used to prevent the header file from being included multiple
times by a single source file, which can be a source of errors.
NOTE: As you save the files after you make changes, Eclipse may attempt to
rebuild the project automatically. This might cause errors to be generated if, for
example, you have modified the header file but not yet done so for the
implementation file. Such errors can be ignored.
b) Since we have provided the definition of the Calculator class for this lab
exercise, you will replace the contents of the generated source files with the code
given below. First, delete the contents of Calculator.h, then copy and paste the
following code into the file:
#ifndef CALCULATOR_H
#define CALCULATOR_H
// CS 2605 Spring 2008 Lab 1
// Fill in the names and PIDs of the members of your pair:
//
//
class Calculator
{
public:
Calculator( int Initial = 0 );
int getValue() const;
void setValue( int Value );
void Add( int Value );
void Subtract( int Value );
void Multiply( int Value );
void DivideBy( int Value );
void Clear();
private:
int mValue;
};
#endif // CALCULATOR_H
c) Delete the contents of Calculator.cpp, then copy and paste the following code
into the file:
#include "Calculator.h"
// --------------------------------------------------------------
Calculator::Calculator( int Initial )
{
setValue( Initial );
}
// --------------------------------------------------------------
int Calculator::getValue() const
{
return mValue;
}
// --------------------------------------------------------------
void Calculator::setValue( int Value )
{
mValue = Value;
}
// --------------------------------------------------------------
void Calculator::Add( int Value )
{
mValue += Value;
}
// --------------------------------------------------------------
void Calculator::Subtract( int Value )
{
mValue -= Value;
}
// --------------------------------------------------------------
void Calculator::Multiply( int Value )
{
mValue *= Value;
}
// --------------------------------------------------------------
void Calculator::DivideBy( int Value )
{
mValue /= Value;
}
// --------------------------------------------------------------
void Calculator::Clear()
{
mValue = 0;
}
Part II: Completing the C++ Program
3. Complete the C++ program
a) As you found in lecture, every C++ program must include a function main() in
which execution begins. Of course, most C++ programs consist of much more
than just main() and a single class. In this exercise, we will also require another
function that will drive the testing of our Calculator class.
Right-click on the Calculator project again, but this time select New / Source File.
Enter the file name "driver.cpp" and click "Finish". This will add a new empty
file to the project. Copy and paste the following code into that file and save it:
#include
#include
#include
#include
using namespace std;
#include "Calculator.h"
void processScript(Calculator& Calc, istream& Script,
ostream& Log);
int main() {
Calculator myCalculator(0);
ifstream Script("CalculatorScript.txt");
ofstream Tape("CalculatorTape.txt");
processScript(myCalculator, Script, Tape);
Script.close();
Tape.close();
return 0;
}
void processScript(Calculator& Calc, istream& Script,
ostream& Log) {
const string EXITCMD = "exit";
string Command;
int Operand;
unsigned int cmdNum = 0;
getline( Script, Command, '\t' );
while ( Script && Command != EXITCMD ) {
Script >> Operand >> ws;
Log << setfill('-') << setw(50) << '-'
<< setfill(' ') << endl;
Log << setw(5) << cmdNum << ": "
<< setw(10) << left << Command << right;
if ( Command != "clear" ) {
Log << setw(16) << Operand;
}
Log << endl;
if ( Command == "add" ) {
Calc.Add( Operand );
}
else if ( Command == "subtract" ) {
Calc.Subtract( Operand );
}
else if ( Command == "multiply" ) {
Calc.Multiply( Operand );
}
else if ( Command == "divide by" ) {
Calc.DivideBy( Operand );
}
else if ( Command == "clear" ) {
Calc.Clear();
}
else {
Log << "The command " << Command
<< " is not recognized." << endl;
}
Log << " calculator display: " << setw(10)
<< Calc.getValue() << endl;
getline(Script, Command, '\t');
}
Log << setfill('-') << setw(50) << '-' << setfill(' ')
<< endl;
}
b) At this point, if you have properly copied the code into the appropriate files and
saved them, the project should build with no errors. Click the "Build All" icon on
the toolbar (if Eclipse didn't perform an automatic build). Then go to the lower-
right corner of the Eclipse window and find the icons for "Problems" and
"Console". Click on both and observe the results. The Problems window should
show 0 errors and 0 warnings. The Console window will show you the output
generated by the g++ compiler and linker when the build was performed. For
example:
**** Build of configuration Debug for project Calculator ****
make all
Building file: ../Calculator.cpp
Invoking: Cygwin C++ Compiler
g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"Calculator.d" -
MT"Calculator.d" -o"Calculator.o" "../Calculator.cpp"
Finished building: ../Calculator.cpp
Building file: ../driver.cpp
Invoking: Cygwin C++ Compiler
g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"driver.d" -
MT"driver.d" -o"driver.o" "../driver.cpp"
Finished building: ../driver.cpp
Building target: Calculator.exe
Invoking: Cygwin C++ Linker
g++ -o"Calculator.exe" ./Calculator.o ./driver.o
Finished building target: Calculator.exe
Part III: Perform some Procedural Testing
4. Use the driver to test your code
a) Repeat the earlier procedure to add a file named "CalculatorScript.txt" to the
project, and copy the contents from the course website:
add 10
add 7
multiply 31
subtract 42
divide by 7
add 3
subtract 1
clear
exit
b) Run your program (Run / Run). This should add a new file to the project, named
"CalculatorTape.txt". Open the file; the contents should be:
--------------------------------------------------
0: add 10
calculator display: 10
--------------------------------------------------
0: add 7
calculator display: 17
--------------------------------------------------
0: multiply 31
calculator display: 527
--------------------------------------------------
0: subtract 42
calculator display: 485
--------------------------------------------------
0: divide by 7
calculator display: 69
--------------------------------------------------
0: add 3
calculator display: 72
--------------------------------------------------
0: subtract 1
calculator display: 71
--------------------------------------------------
0: clear
calculator display: 0
--------------------------------------------------
The file "CalculatorScript.txt" was parsed by the given code in main() and
processScript(), and this file was produced.
5. Expand your testing and submit to the Curator
a) Modify the script file to execute different sequences of commands for the
Calculator and see whether the results appear to be correct. You should perform a
number of these tests, and validate the results by hand and/or using a calculator.
b) Once you're satisfied you don't see any errors in your own tests, submit your
Calculator class to the Curator for automated testing.
Create a zip file containing the files Calculator.h and Calculator.cpp
(and absolutely no other files). It doesn't matter what you call your file.
Go to the Curator Project website (www.cs.vt.edu/curator/) and click on
the link for the index of Curator servers, and then click on the submit link for CS
2605. The driver for this part should then log on to the Curator and submit the zip
file to the Curator under the heading Lab01PartIII.
View the grade report and check the results from the Curator's testing. If you
haven't achieved the maximum score of 500 (which means you didn't copy/paste
the given code correctly), examine the test output to determine where the errors in
your source code were, fix them, create a new zip file, and submit again.
It shouldn't take you long to achieve a perfect score. Each student will be allowed
to make up to 25 submissions to the Curator.
Both members of your pair must eventually submit the Calculator class files to the
Curator. You may alternate who submits until you get a perfect score, or not.
Part IV: Perform some Unit Testing with CxxTest
6. Create a CxxTest suite to hold your tests
a) Repeat the procedure in Part I to create a new Eclipse project, called Calculator2,
but this time select the option "Empty Project with CxxTest".
b) Using Windows Explorer, copy the files Calculator.h and
Calculator.cpp from the earlier project into this one. Do not copy any other
files!
c) You will now create a CxxTest suite that will hold your unit tests to verify that the
Calculator class works as intended. As was the case with JUnit in Java, we
provide a wizard in Eclipse to assist in the creation of CxxTest suites. Since we
want to test the class declared in Calculator.h, right-click on that file in the
project, then choose New / CxxTest Suite from the menu. You will see that the
"Header under test" field has been set to point to the selected file. In the "Name"
field, enter "CalculatorTest" (without the quotes), then click "Next."
d) You may now choose the methods in the Calculator class, if any, for which you
wish to have empty stub functions generated. For now, let us test the four
arithmetic operations — so, place checkmarks next to the Add, Subtract,
Multiply, and divideBy methods in the list, and click "Finish."
Notice that the generated file has placeholders for the method code in the header
file itself, rather than in an implementation file; indeed, no implementation file
was generated for the test suite. As was mentioned previously, it is possible for a
C++ class to have the method code implemented in the header file rather than the
implementation file (as in Java's single file approach), but this is usually reserved
for very simple functions or classes. In this course, we implement the test
methods directly in the test class in the header file for the sake of simplicity (for
test classes only).
As with JUnit, any method whose name begins with test will be executed as a
test case when you build your project. This allows you to provide private helper
functions that you can call from multiple test cases by giving it a name that is not
prefixed with test.
7. Implement and use your first test
a) The first test that we will implement will test the behavior of the add function. To
do this, we will create a Calculator object with a default value, call the add()
method to add a quantity to that value, and then use the getValue() method to
retrieve the final value.
In order to check that the value is equal to our expectation, we use the CxxTest
macro TS_ASSERT_EQUALS(x, y), where x and y are the values that we wish to
compare. If x and y are unequal, then the test fails and a message indicating this
will be shown in the CxxTest view in Eclipse. Similarly to JUnit, CxxTest has a
set of macros of the form TS_ASSERT_() that check whether some
Condition is true.
To implement the test for the add() method, find the testAdd() method in
CalculatorTest.h. The body of the method will contain a comment:
// TODO: Implement testAdd() function.
Replace this comment with the following code fragment, which creates a new
Calculator object named calc with value 6, adds 2 to it, then verifies that the
result is 8:
Calculator Calc( 6 );
Calc.Add( 2 );
TS_ASSERT_EQUALS( Calc.getValue(), 8 );
b) When you save your changes to CalculatorTest.h, Eclipse will again
automatically build the project, and once finished it will run all the tests in the
project. If you made no errors, you will see that the progress bar in the CxxTest
view is green, indicating success.
c) Expand the CalculatorTest entry in the test hierarchy of the CxxTest view.
You will see green checkmarks next to each of the tests, indicating that they all
succeeded. Also note that the testSubtract, testMultiply, and
testDivideBy tests succeeded by virtue of the fact that they did not contain
any assertions that could fail.
8. Implement More Tests
a) Implement the remaining three test methods in a similar fashion to the one above.
b) Modify one or more of your existing tests so that they will intentionally fail. What
kind of visual feedback do you see in the source editor and the CxxTest view?
Enter your description of this as a comment preceding the corresponding test
code.
c) When you are done, create another zip archive containing the files
Calculator.h, Calculator.cpp and CalculatorTest.h and upload
that to the Curator under the heading Lab01PartIV. Again, both members of your
pair must make this submission. Note that this will not be automatically graded
by the Curator, but it will be reviewed by the TA.
Backup Lab Work
Before leaving the lab both you and your partner should backup your submitted lab work . It is
your responsibility to be able to produce a copy of your work. Relying on the Curator or lab
servers is dangerous. A USB key or emailing yourself a copy of your submitted archive are good
options.
If You Finish Early
If you and your partner finish both parts of this assignment early, spend some time familiarizing
yourself more with CxxTest. TS_ASSERT_EQUALS is one of the most common assertions that you
will use, but there are others that can be useful as well: TS_ASSERT_DIFFERS checks that two
quantities are unequal; TS_ASSERT_LESS_THAN checks that the first quantity is less than the
second; TS_ASSERT_LESS_THAN_EQUALS, that the first is less than or equal to the second; and
TS_ASSERT, which takes a Boolean expression as its single argument and verifies that it evaluates
to true.
Review the CxxTest User's Guide linked off the course home page. It contains full details on the
available assertions.