Using CXXTest with VC6 and VC7 at the command line

This can be a pig to set up out of the box.  I did get it working, tho, and here's how.  I was using Eclipse as my editor.

Directory structure

    c:---> workspace----->cxxtest

The cxxtest directory is where cxxtest is unpacked.  It contains the supplied directories cxxtest, docs and sample.  This is all out of the box.

My code (.cpp, .h) is in the src directory. 

My unit tests are in .h files in the tests directory.

The testDict directory is not necessary.  It contains a VC6 console project, created using the VS6 IDE, which has a single .cpp file, and includes other files from the src directory.  The point of this is to ensure that I can debug code using the IDE when I want to.  It has no other connection to cxxtest.  However the instructions to compile it are also in the Makefile below.

The <files> are:


The Makefile works with Microsofts nmake, cl and link commands.  Here it is:

#	To run:
#	Start|Run|cmd
#	cd \workspace\engine
#	vcvars32.bat (for 6.0 ) [or vsvars32.bat for 7 -- perf tests show code runs faster under 6]
#	nmake clean
#	nmake
#	nmake tests
#	Common problems:
#	1: If you get a link error with XLen in std lib, it's because you have VC6 includes ahead of VC7 ones in the include variable
#   2: error: runner.cpp
#      atlconv.h(48) : error C2065: '_ASSERTE' : undeclared identifier
#	   This one is cured by #include "windows.h" -- if you want to do that!

ALL : testDict
	@echo erasing unwanted files
	-@erase "$(BIN_DIR)\testDict.ilk"
	-@erase "$(BIN_DIR)\testDict.pdb"
	-@erase /Q "tests\*op*.txt"
	@echo "Running code"

	-@erase /Q "tests\*tempfiles*.txt"
	-@erase "$(SRC_DIR)\runner.cpp"
	-@erase /Q "$(OBJ_DIR)\*.*"
	-@erase /Q "$(BIN_DIR)\*.exe"

#	* CXX_Test


#	* Create temporary directories
!IF "$(OS)" == "Windows_NT"

#  These targets are dependencies on the compile and link, just to check directories exist
"$(BIN_DIR)" :
    if not exist "$(BIN_DIR)/$(NULL)" mkdir "$(BIN_DIR)"

"$(OBJ_DIR)" :
    if not exist "$(OBJ_DIR)/$(NULL)" mkdir "$(OBJ_DIR)"

#	Link

LINK32_LIBS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
LINK32_OPTS_DEBUG=/nologo /subsystem:console /incremental:yes /debug /machine:I386
#LINK32_OPTS_RELEASE= /nologo /subsystem:console /incremental:no /machine:I386

	"$(OBJ_DIR)\myfile1.obj" \
	"$(OBJ_DIR)\myfile2.obj" \

testDict : "$(BIN_DIR)" $(DEF_FILE) $(LINK32_OBJS)

#	Include file of other file dependencies for link step

!IF "$(NO_EXTERNAL_DEPS)" != "1"
!IF EXISTS("$(HOME_DIR)\testDict.dep")
!INCLUDE "$(HOME_DIR)\testDict.dep"
!MESSAGE Warning: cannot find "$(HOME_DIR)\testDict.dep"

#	Compile step (/c = no link)


#CPP_PROJ=/nologo /MLd /W3 /Gm /GX /ZI /Od $(MYINCLUDES) $(MYDEBUGDEFINES) /Fo"$(OBJ_DIR)\\" /Fd"$(OBJ_DIR)\\" /FD /GZ /c
CPP_PROJ=/EHsc /nologo /ML /W3 /GX /O2 $(MYINCLUDES) $(MYRELEASEDEFINES) /Fo"$(OBJ_DIR)\\" /Fd"$(OBJ_DIR)\\" /FD /c

#	Each step must have a target with the .obj name (referenced in the testDict dependencies above)
#	Each target is of the form : 
"$(OBJ_DIR)\myfile1.obj" : $(SOURCE) "$(OBJ_DIR)"

"$(OBJ_DIR)\myfile2.obj" : $(SOURCE) "$(OBJ_DIR)"

"$(OBJ_DIR)\testDict.obj" : $(SOURCE) "$(OBJ_DIR)"

#	Test Runner

	"$(OBJ_DIR)\runner.obj" \
	"$(OBJ_DIR)\myfile1.obj" \


# Main tests target
tests: $(BIN_DIR)\runner.exe
	@echo "running tests"
	-@erase $(RUNNER_SOURCE)

"$(BIN_DIR)\runner.exe" : "$(BIN_DIR)" $(RUNNER32_OBJS) $(SRC_DIR)\runner.cpp
    $(LINK32) /out:"$(BIN_DIR)\runner.exe" $(LINK32_LIBS) $(LINK32_OPTS) $(RUNNER32_OBJS)

# Runner.cpp depends on anything in the tests dir changing
# Create runner.cpp
"$(OBJ_DIR)\runner.obj": $(RUNNER_SOURCE) "$(OBJ_DIR)" $(TESTS)

	--runner=ParenPrinter \
	--have-eh             \

	@echo "Creating runner.cpp"

Running the tests

To run this:

  1. Open a console (Start|Run|Cmd)
  2. cd \workspace\engine
  3. set the environment variables.  Enter vcvars32 or vsvars32 depending on which you want to run (both will work, but VC7 seems slower) and hit enter.
  4. nmake clean  (to remove debris)
  5. nmake tests (to run the tests)
  6. nmake (to compile the test program testDict)

Sample tests

This file is some of the tests for some code of mine called timer_util.h and timer_util.cpp, which contains a class QLTimer.  This is a stopwatch class, which measures time.  It has two methods, StartTimer() and StopTimer(), and two others getTicksElapsed() and getSeconds() to tell you how long the time interval between the two.


#include 		// for cout
#include      // for sleep()
#include "timer_util.h"
using namespace std;

class TimerUtilTest : public CxxTest::TestSuite

   	QLTimer * myObj;

	void setUp( void )
		myObj = new QLTimer();

	void tearDown( void )
		delete myObj;

    void testTimer( void )
        TS_ASSERT_EQUALS( myObj->getTickFrequency(), "Ticks are 0 3579545 per second" );
        TS_ASSERT_EQUALS( myObj->getTicksElapsed(), 0 );
        TS_ASSERT_EQUALS( myObj->getSeconds(), 0.0 );

        for (int i=0;i<10000;i++){}

        TS_ASSERT( myObj->getTicksElapsed() < 200 );


    void testTimer2( void )

        Sleep(1000);  // millisecs; sleep() on unix

        cerr << "Time in Seconds to wait 1000 millisec=" << myObj->getSeconds() << endl;
        TS_ASSERT( myObj->getSeconds() > 0.9 );



I hope that is helpful.  Getting that makefile to work took two days, but it really isn't too hard once you have all the options for the compiler.

You can add extra include directories on to the end easily enough, if you have your .h's in other places.  If you have .cpp's in other places which you need to link in, create a MYSRC_DIR variable, and point it to that directory; then make sure the extra .cpp files are specified being in $(MYSRC_DIR) rather than in $(SRC_DIR) as mine are in the above example.

Constructive feedback is welcomed to Roger Pearse.

This page has been online since 30th November 2006.

Return to Roger Pearse's Pages