Home
Name Modified Size InfoDownloads / Week
ReadMe.txt 2010-02-14 11.4 kB
UnitTestForC.zip 2010-02-14 89.1 kB
SetupUnitTestForC.exe 2010-02-14 476.0 kB
Totals: 3 Items   576.5 kB 1
Unit Test for C - Version 1.01
Copyright 1993-2010 by Todd Osborne
Publicly Released February 14, 2010

The author of this software is Todd Osborne (toddosborne@gmail.com), and
updates and other information about this package can be found on the web
at http://www.toddtown.com.
   
This software is public domain. You may use it as you see fit, in free
and open source software, commercial closed source software, or any other
type of software. I request, but do not demand, that you give me credit for
this work as you see fit in your application. If you find bugs in this
software, I would greatly appreciate you reporting them to me. If you make
additions to this software that you feel would benefit the public as a
whole, kindly submit your changes to me for review.
   
Unit Test for C is a simple, yet very useful and effective, software
development tool for C and C++ programmers. It is designed to provide a
great deal of basic functionality in a very small package. It functions nearly
identically on Windows and UNIX systems. I personally test it on Windows with
Microsoft Visual Studio, and on Apple Macintosh OS X with GCC.

THE BASICS
----------
Normally, unit testing is performed in a project designated for that purpose.
In other words, the unit testing code is not compiled into your real
application, but into a separate project for the sole purpose of testing your
code. Unit Test for C does not require this, though it is highly recommended.

The idea behind unit testing is that you will create multiple simple tests that
you "assert" will either succeed or fail. Unit test code should be easy to
read, substantially favoring ease of understanding over high quality or more
obscure code. Unit Test for C has several functions and helper macros to assist
you with these assertions. Take the following function for example:

int SomeFunctionThatReturnsOne()
{
    return 1;
}

Assume that you have a function that, like the above function, should always
return 1. Any other return value indicates the function failed to perform
correctly. A unit test for this function could look like this:

void SomeFunctionThatReturnsOneTest()
{
    UtcAssertAreEqualInt(1, SomeFunctionThatReturnsOne());
}

The test will pass, because the first parameter passed to UtcAssertAreEqualInt
is 1 (the expected correct value), and the return value from the
SomeFunctionThatReturnsOne() is 1. You have asserted that you expect 1 to be
returned, anything else would indicate an error.

So now at some later date, Bill the really excellent programmer comes along and
decides to refactor SomeFunctionThatReturnsOneTest() to make it "better". He
changes it to be:

int SomeFunctionThatReturnsOne()
{
    return 2;
}

Now the unit test will fail, since 2 was returned from the function but 1 was
the expected value. Granted, this is a trivial case, but the idea is the same
no matter the complexity of the code. Unit Test for C has many AssertXXX()
type functions and macros, covering all native C data types including bools,
ints, longs, floats, doubles, pointers, strings and unsigned types. It also has
functions for forcing a test to fail (UtcAssertFail), and many others.

There does not need to be a single assertion per test, you can have as many
as you like. Take a slightly more complex function:

int SomeFunctionThatReturnsTheParameter(int parameter)
{
    return parameter;
}

and the associated unit test for it:

void SomeFunctionThatReturnsTheParameterTest()
{
    UtcAssertAreEqualInt(1, SomeFunctionThatReturnsTheParameterTest(1));
    UtcAssertAreEqualInt(2, SomeFunctionThatReturnsTheParameterTest(2));
    UtcAssertAreEqualInt(3, SomeFunctionThatReturnsTheParameterTest(3));
}

Here a single unit test has 3 assertions, a perfectly valid unit test. When
reporting the output of the test, the report will clearly show a single unit
test that passed, with 3 assertions that passed, and how long the test took
to run.

UTC FUNDAMENTAL CONCEPTS
------------------------
As far as unit testing goes, UTC does not change many of the rules or customs.
The only paradigm not typically found in most unit testing tools is the concept
of "batches". A batch is nothing more than a group of related functions, an
organizational abstraction that allows you to keep your tests more focused. For
example, if you have a group of 10 functions that are all memory management
related, "Memory Management" would make a logical batch name, a collection if
you will of functions like TestMemAlloc() and TestMemFree(). If you are testing
C++ code, a likely candidate for a batch name would be the name of the class
you are testing so a C++ class named "Array" could have a batch with the same
name and test functions such as "Add", "Remove", and "Clear".

UTC requires the use of batches, as they the "parent" or "own" of test functions.
However, if you do not wish to create your own named batches, test functions can
exist in a default batch that UTC will create automatically as needed.

Another feature of batches is that they can have functions that are run before
and after each batch is run, and before and after each test function in a batch
is run. This makes the wrappering of startup and teardown code much easier to
implement.

MODES OF OPERATION
------------------
First Mode - Windows and UNIX
    Create a console mode project that contains your unit tests and include
    UnitTestForC.c in this project. In your main() function, create the batches
    needed using UtcCreateBatch() and UtcBatchAddFunction(). Tell UTC to run the
    tests using UtcBatchRunAll(). Call UtcReportCreate() to create an XML
    report that contains the test results. This can either be send to stdout,
    or sent to a file.
            
Second Mode - Windows Only
    Perform the same steps as the first mode, but do not include UnitTestForC.c
    in the project. Instead, link against the UnitTestForC32.lib (32-bit) or
    UnitTestForC64.lib (64-bit) import library. Your application works
    identically, but UTC is not directly compiled into your code. Make sure that
    UnitTestForC32.dll and/or UnitTestForC64.dll is in your path, or install it
    into the Windows directory.
    
Third Mode - Windows Only (Using the Windows Unit Test for C application)
    This mode is very similar to the second mode, with the biggest exception
    being your project will not create an EXE application, but will instead
    generate a DLL file that can be loaded by Windows Unit Test for C. Perform
    the same steps as the second mode, but change your project type from
    creating an EXE to creating a DLL. The main() function will no longer be
    used, so rename it to UtcLibraryCreateBatches() with a void return type.
    You should still create your UTC batches in this function, but it will be
    called from Windows Unit Test for C. Now launch Windows Unit Test for C
    and you will be able to load your DLL, determine which tests to run, easily
    view the test results, and save the report as an XML file.

PUTTING IT ALL TOGETHER
-----------------------
Now that you have an overview of how the product works, I will now demonstrate
a complete unit test application that uses Unit Test for C with inline comments
to provide more information. The following is a complete "main.c" module for
testing 2 functions implemented elsewhere, called Function1() and Function2():

// Include the header that defines Function1() and Function2().
#include "MyHeader.h"

// Include Unit Test for C.
#include "UnitTestForC.h"

// This tests a function named Function1() implemented in another file.
// Function1() returns 1 on success.
void Function1Test()
{
    // Function1() returns 1 on success, and we are expecting success.
    UtcAssertAreEqualInt(1, Function1());
}

// This tests a function named Function2() implemented in another file.
// Function2() returns a pointer on success, NULL on failure.
void Function2Test()
{
    // Function2() returns a pointer on success, and we are expecting success.
    UtcAssertIsNotNull(Function2());
}

// This is the main entry point to the executable.
void main()
{
    // Define a batch.
    UTCBatch batch = UtcBatchCreate("MyBatch");
    
    // Add the 2 test functions above to the batch.
    UtcBatchAddFunction(batch, Function1Test);
    UtcBatchAddFunction(batch, Function2Test);
    
    // Run the unit tests.
    UtcBatchRunAll();
    
    // Generate an XML report of all failures and passed assertions, with
    // summary information, and send it to stdout.
    UtcReportCreateStream(UTC_REPORT_ALL, stdout);
    
    // Free all memory used by UTC.
    UtcBatchFreeAll();
}

FINER POINTS
------------

1) The UTC_ and Utc prefixes on macros, types, functions, etc. is to avoid
   namespace collisions.

2) The original project name was C Unit Test. My wife slapped me because of
   the acronymn :-)
   
3) All AssertXXX() macros call real C functions with the same name, with
   Imp (Implement) suffixed. This is because if they were entirely implemented
   as macros you could not pass the result of function calls to them, the
   function itself could be called multiple times during macro expansion, a
   behaviour that is almost certainly undesirable.

4) All public-facing functions validate parameters and run state. Internal
   functions perform their own validation during debug builds only, using the
   standard assert() macro.

5) The copyright is correct. I started this project in 1993, used it in various
   projects over the years, and rekindled and expanded it greatly for testing
   a major commercial software application. I never planned to release it, but
   figured many more people may find it useful, especially after looking at
   the quality and (lack of) completeness of existing C unit testing tools.

6) It's not what you take when you leave this world behind you, it's what you
   leave behind you when you go. Kids matter, code matters. Kids matter more,
   may you use this software to increase your development speed and quality,
   so that you can spend more time with your children and less in front of the
   computer.

7) Use WindowsUnitTestForC32.exe for testing 32-bit Windows code, and
   WindowsUnitTestForC64.exe for testing 64-bit Windows code. They cannot test
   code compiled with different "bitness".

8) The code was written over a period of 16 years, the documentation in about 2
   hours. Quite frankly, I did not want to spend a lot of time writing the
   documentation if nobody was interested in using it. If there becomes an
   audience for this software I will expand the documentation. The source code
   is heavily commented and all source code and unit tests are provided in the
   distribution.

RELEASE HISTORY POINTS
----------------------

Version 1.01 - February 14, 2010
   Fixed bug where UtcAssertIsTrue() and UtcAssertIsFalse() could be confused
   by a compiler that defines boolean value differently due to optimizations.
   The code no longer looks for true == true to determine if a value is true,
   but rather looks for value != false to make this determination. Vice-versa
   for testing for false.

Version 1.00 - November 22, 2009
Source: ReadMe.txt, updated 2010-02-14