Tags:
create new tag
view all tags

CuTest

eSDO will use the CuTest package for unit testing. CuTest is a simple framework that allows developers to include unit test methods within source classes as they are coded. All unit tests within a src directory can be executed by compiling and running a single instance of AllTests.c All test suites included in a src directory's AllTests.c should pass.

30 September 2006: at least one CuTest method for each method in all C classes within each algorithm's src directory.

December 31: thorough CuTest methods for each method in all C classes within each algorithm's src directory.

Links

Procedure

  1. Download the CuTest package from SourceForge.
  2. Unzip CuTest in a convenient directory (README contains instructions and a good introductory tutorial).
  3. Copy AllTests.c, CuTest.c and CuTest.h into your src directory.
  4. Add CuTest unit test methods inside each C class in your src directory.
    • Write at least one CuTest unit test method for each method in the C class.
    • OpenPBX lists several of the CuTest methods available in CuTest.h (note: I've only tried out a few).
    • Geosoft offers an excellent guide to writing unit tests. Although this guide is geared towards java, similar principles apply. For example, methods with numerical inputs should be tested with postives, negatives, 0, infinity, not a number values, and values greater or smaller than the range expected by the method.
  5. Add a getTestSuite method to the C class.
  6. Add a link to your test suite in AllTests.c (see README tutorial for example).
  7. Run tests:
    % gcc -o AllTests.out AllTests.c CuTest.c YourClass.c
    % ./AllTests.out
  8. Be sure to upload all C classes with added unit tests to CVS.

Example

The following example uses the class normal.c from the eSDO CoronalLoops src directory. A copy of this class containing the following unit tests is attached to this page as normal2.c.

The class normal.c contains one method: double normal(double x), which computes the normal distribution of a given number. This method accepts a double variable as input, so the unit tests should ensure that the method can handle unexpected inputs (numbers outside the expected value range, NaNs, infinity, etc, plus expected positives, negatives and zero). We will create one unit test method for each of these tests.

    void TestNormal(CuTest *tc) {
        double input = 0.67;
        double actual = normal(input);
        double expected = 0.748571;
        CuAssertDblEquals(tc, expected, actual, 0.001);
    }

    void TestNormal_NaNInput(CuTest *tc) {
        double actual = normal(10.0/0.0);
        double expected = 1.0;
        CuAssertDblEquals(tc, expected, actual, 0.0);
    }

    void TestNormal_NegativeInput(CuTest *tc) {
        double actual = normal(-1.0);
        double expected = 0.158655;
        CuAssertDblEquals(tc, expected, actual, 0.001);
    }

    void TestNormal_ZeroInput(CuTest *tc) {
        double actual = normal(0.0);
        double expected = 0.5;
        CuAssertDblEquals(tc, expected, actual, 0.0);
    }


    void TestNormal_HighInput(CuTest *tc) {
        double input = 145669999;
        double actual = normal(input);
        double expected = 1.0;
        CuAssertDblEquals(tc, expected, actual, 0.001);
    }

Now we must add a "GetSuite" method to normal.c so that AllTests will know which unit test methods belong in the normal class's test suite. Append the class's name to "GetSuite" to construct an obvious method name.

    CuSuite* NormalGetSuite() {
        CuSuite* suite = CuSuiteNew();
        SUITE_ADD_TEST(suite, TestNormal);
        SUITE_ADD_TEST(suite, TestNormal_NaNInput);
        SUITE_ADD_TEST(suite, TestNormal_NegativeInput);
        SUITE_ADD_TEST(suite, TestNormal_ZeroInput);
        SUITE_ADD_TEST(suite, TestNormal_HighInput);
        return suite;
    }

Now call the normal class's GetSuite method from AllTests.c:

#include "CuTest.h"
CuSuite* NormalGetSuite();

void RunAllTests(void) {
  CuString *output = CuStringNew();
  CuSuite* suite = CuSuiteNew();
  CuSuiteAddSuite(suite, NormalGetSuite());
  CuSuiteRun(suite);
  CuSuiteDetails(suite, output);
  printf("%s\n", output->buffer);
}
int main(void) {
  RunAllTests();
}

Finally, compile AllTests.c and normal.c and run the tests:

% gcc -o AllTests.out AllTests.c CuTest.c normal2.c -lm
% ./AllTests.out
OK (5 tests)

If one or more unit tests fail, the message will look like this:

% ./AllTests.out
There was 1 failure:
1) TestNormal_ZeroInput: normal2.c:271: expected <0.000000> but was <0.500000>

!!!FAILURES!!!
Runs: 5 Passes: 4 Fails: 1

Further guidelines and schedule

  • When to write unit tests: Unit tests do not need to be written for inherited, unmodified methods. Unit tests do need to be written for original methods as well as inherited methods that have been modified.
  • Initially, each src directory should have its own AllTests.c class until automatic daily builds are executed over the eSDO CVS.
  • September 30: at least one CuTest method for each method in all C classes within each algorithm's src directory. All tests should pass when that src directory's AllTests.c is run.
  • December 31: thorough CuTest methods for each method in all C classes within each algorithm's src directory. All tests should pass when that src directory's AllTests.c is run.

-- ElizabethAuden - 31 Jan 2006

Topic attachments
I Attachment History Action Size Date Who Comment
C source code filec AllTests.c r1 manage 0.4 K 2006-03-03 - 16:30 ElizabethAuden  
Header fileh CuTest.h r1 manage 3.9 K 2006-03-03 - 16:30 ElizabethAuden  
C source code filec CuTestTest.c r1 manage 17.8 K 2006-03-03 - 16:30 ElizabethAuden  
Unknown file formatEXT README r1 manage 6.9 K 2006-03-03 - 16:30 ElizabethAuden  
C source code filec normal2.c r1 manage 7.3 K 2006-08-04 - 00:23 ElizabethAuden CoronalLoop normal.c class with added unit tests
Edit | Attach | Watch | Print version | History: r3 < r2 < r1 | Backlinks | Raw View | More topic actions
Topic revision: r3 - 2006-08-04 - ElizabethAuden
 
This site is powered by the TWiki collaboration platform Powered by PerlCopyright © 2008-2019 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback