Unit Testing Frameworks


Now that we ve identified the scope of the unit test, let s look at some unit testing frameworks to explore how they can be used to increase the quality of our software. The following are the frameworks we ll review.

  • Brew your own

  • C unit test (cut) system

  • Embedded unit test

  • expect

Brew Your Own

Building your own simple unit test framework is not difficult to do. Even the simplest architecture can yield great benefits. Let s look at a simple architecture for testing a software unit.

Consider that we have a simple stack module with an API consisting of the following:

 typedef struct { ... } stack_t;    int stackCreate(stack_t *stack, int stackSize);    int stackPush(stack_t *stack, int element);    int stackPop(stack_t *stack, int *element);    int stackDestroy(stack_t *stack); 

This very simple LIFO stack API permits us to create a new stack, push an element on the stack, pop an element from the stack, and finally destroy the stack. Listing 24.1 shows the code (  stack.c ) for this simple module, and Listing 24.2 shows the header file (  stack.h ).

Listing 24.1: Stack Module Source (on the CD-ROM at ./source/ch24/byo/stack.c )
start example
  1:  #include <stdlib.h>  2:  #include "stack.h"  3:   4:   5:  int stackCreate(stack_t *stack, int stackSize)  6:  {  7:  if ((stackSize == 0)  (stackSize > 1024)) return -1;  8:   9:  stack->storage = (int *)malloc(sizeof(int) * stackSize);  10:   11:  if (stack->storage == (void *)0) return -1;  12:   13:  stack->state = STACK_CREATED;  14:  stack->max = stackSize;  15:  stack->index = 0;  16:   17:  return 0;  18:  }  19:   20:   21:  int stackPush(stack_t *stack, int element)  22:  {  23:  if (stack == (stack_t *)NULL) return -1;  24:  if (stack->state != STACK_CREATED) return -1;  25:  if (stack->index >= stack->max) return -1;  26:   27:  stack->storage[stack->index++] = element;  28:   29:  return 0;  30:  }  31:   32:   33:  int stackPop(stack_t *stack, int *element)  34:  {  35:  if (stack == (stack_t *)NULL) return -1;  36:  if (stack->state != STACK_CREATED) return -1;  37:  if (stack->index == 0) return -1;  38:   39:  *element = stack->storage[stack->index];  40:   41:  return 0;  42:  }  43:   44:   45:  int stackDestroy(stack_t *stack)  46:  {  47:  if (stack == (stack_t *)NULL) return -1;  48:  if (stack->state != STACK_CREATED) return -1;  49:   50:  stack->state = 0;  51:  free((void *)stack->storage);  52:   53:  return 0;  54:  } 
end example
 
Listing 24.2: Stack Module Header File (on the CD-ROM at ./source/ch24/byo/stack.h )
start example
  1:  #define STACK_CREATED   0xFAF32000  2:   3:  typedef struct {  4:   5:  int state;  6:  int index;  7:  int max;  8:  int *storage;  9:   10:  } stack_t;  11:   12:   13:  int stackCreate(stack_t *stack, int stackSize);  14:   15:  int stackCreate(stack_t *stack, int element);  16:   17:  int stackPop(stack_t *stack, int *element);  18:   19:  int stackDestroy(stack_t *stack); 
end example
 

Let s look at a simple regression that when built with this stack module can be used to verify that it works as expected. Since there are many individual tests that can be used to validate this module, we ll concentrate on just a few to illustrate the approach.

First, in this regression, we provide two infrastructure functions as wrappers for the regression. The first is a simple main function that invokes each of the tests, and the second is a result checking function. The result checking function simply tests the result input, and if zero, the test failed, otherwise the test passed. This function is shown in Listing 24.4 (we ll look at its use shortly).

We declare a failed integer, which will be used to keep track of the number of actual failures. This is used by our main , which allows it to determine if the regression passed or failed. The checkResult function ( Listing 24.3) takes two inputs; a test number and the individual test result. If the test result is zero, then we mark the test as failed (and increment our failed count); otherwise the test passed (result is nonzero), and we indicate this.

Listing 24.3: Result Checking Function for a Simple Regression (on the CD-ROM at ./source/ch24/byo/regress.c )
start example
  1:  int failed;  2:   3:  void checkResult(int testnum, int result)  4:  {  5:  if (result == 0) {  6:  printf("*** Failed test number %d\n", testnum);  7:  failed++;  8:  } else {  9:  printf("Test number %2d passed.\n", testnum);  10:  }  11:  } 
end example
 

Our main program simply calls our regression tests in order, clearing the failed count (as shown in Listing 24.4).

Listing 24.4: Simple Regression main (on the CD-ROM at ./source/ch24/byo/regress.c )
start example
  1:  int main()  2:  {  3:   4:  failed = 0;  5:  test1();  6:   7:  return 0;  8:  } 
end example
 

Now let s look at a regression that focuses on creation and destruction of stacks. As we saw in the stack module source, there are numerous ways that a stack creation and destruction can fail. This test tries to address each of them so that we can convince ourselves that it s coded properly (see Listing 24.5).

In this regression, we call an API function with a set of input data and then check the result. In some cases, we pass good data, and in others we pass data that will cause the function to exit with a failure status. Consider lines 8 “9, which test stack creation with a null stack element. This creation should fail and return -1. At line 9, we call checkResult with our test number (first argument) and then the test result as argument two. Note here that we test the ret variable with -1, since that s what we expect for this failure case. If ret wasn t -1, then the expression results in 0, indicating that the test failed. Otherwise, if ret is -1, the expression reduces to 1, and the result is a pass.

Our regression also explores the stack structure in order to ensure that the creation function has properly initialized the internal elements. At line 20, we check the internal state variable to ensure that it has been properly initialized with STACK_CREATED .

Listing 24.5: Stack Module Regression Focusing on Creation and Destruction (on the CD-ROM at ./source/ch24/byo/regress.c )
start example
  1:  void test1(void)  2:  {  3:  stack_t myStack;  4:  int ret;  5:   6:  failed = 0;  7:   8:  ret = stackCreate(0, 0);  9:  checkResult(0, (ret == -1));  10:   11:  ret = stackCreate(&myStack, 0);  12:  checkResult(1, (ret == -1));  13:   14:  ret = stackCreate(&myStack, 65536);  15:  checkResult(2, (ret == -1));  16:   17:  ret = stackCreate(&myStack, 1024);  18:  checkResult(3, (ret == 0));  19:   20:  checkResult(4, (myStack.state == STACK_CREATED));  21:   22:  checkResult(5, (myStack.index == 0));  23:   24:  checkResult(6, (myStack.max == 1024));  25:   26:  checkResult(7, (myStack.storage != (int *)0));  27:   28:  ret = stackDestroy(0);  29:  checkResult(8, (ret == -1));  30:   31:  ret = stackDestroy(&myStack);  32:  checkResult(9, (ret == 0));  33:   34:  checkResult(10, (myStack.state != STACK_CREATED));  35:   36:  if (failed == 0) printf("test1 passed.\n");  37:  else printf("test1 failed\n");  38:  } 
end example
 

At the end of this simple regression, we indicate whether the entire test passed (all individual tests passed) or failed. A sample run of the regression is illustrated as:

 # gcc -Wall -o test regress.c stack.c    # ./test    Test number  0 passed.    Test number  1 passed.    Test number  2 passed.    Test number  3 passed.    Test number  4 passed.    Test number  5 passed.    Test number  6 passed.    Test number  7 passed.    Test number  8 passed.    Test number  9 passed.    Test number 10 passed.    test1 passed.    # 

While this method is quite simple, it s also very effective and permits the quick revalidation of a unit after changes are made. Once we ve run our regression, we can deliver it safely with the understanding that we re less likely to break the software that uses it.




GNU/Linux Application Programming
GNU/Linux Application Programming (Programming Series)
ISBN: 1584505680
EAN: 2147483647
Year: 2006
Pages: 203
Authors: M. Tim Jones

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net