Looking for the latest version? Download Version 1.01 (89.1 kB)
Home
Name Modified Size Downloads / Week Status
Totals: 3 Items   576.5 kB 10
ReadMe.txt 2010-02-14 11.4 kB 55 weekly downloads
UnitTestForC.zip 2010-02-14 89.1 kB 44 weekly downloads
SetupUnitTestForC.exe 2010-02-14 476.0 kB 11 weekly downloads
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