(七)cmockery中的key_value分析

所分析的key_value.c和key_value_test.c文件位于 工程中的 cmockery/src/example/ 目录下,是关于setup方法和teardown方法的一个应用,其中setup方法是在进行单元测试之前所做的预备工作,teardown是在单元测试之后所做的清理工作。
key_value.c
  1. #include <stddef.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. typedef struct KeyValue {
  5. unsigned int key;
  6. const char* value;
  7. } KeyValue;
  8. static KeyValue *key_values = NULL;
  9. static unsigned int number_of_key_values = 0;
  10. void set_key_values(KeyValue * const new_key_values,
  11. const unsigned int new_number_of_key_values) {
  12. key_values = new_key_values;
  13. number_of_key_values = new_number_of_key_values;
  14. }
  15. // Compare two key members of KeyValue structures.
  16. int key_value_compare_keys(const void *a, const void *b) {
  17. return (int)((KeyValue*)a)->key - (int)((KeyValue*)b)->key;
  18. }
  19. // Search an array of key value pairs for the item with the specified value.
  20. KeyValue* find_item_by_value(const char * const value) {
  21. unsigned int i;
  22. for (i = 0; i < number_of_key_values; i++) {
  23. if (strcmp(key_values[i].value, value) == 0) {
  24. return &key_values[i];
  25. }
  26. }
  27. return NULL;
  28. }
  29. // Sort an array of key value pairs by key.
  30. void sort_items_by_key() {
  31. qsort(key_values, number_of_key_values, sizeof(*key_values),
  32. key_value_compare_keys);
  33. }
该文件中有4个待测试函数以及一个结构体
set_key_values函数实现给静态全局变量进行赋值成为一个键值对。
key_value_compare_keys函数用于比较键值对集合中的两个键值的大笑
find_item_by_value用于在键值对集合中根据特定的键值返回所对应的数值的键值对,未找到则返回NULL。
sort_items_by_key根据键值调用qsort对集合进行排序。

key_value_test.c
  1. #include <stdarg.h>
  2. #include <stddef.h>
  3. #include <setjmp.h>
  4. #include <string.h>
  5. #include "cmockery.h"
  6. /* This is duplicated here from the module setup_teardown.c to reduce the
  7. * number of files used in this test. */
  8. typedef struct KeyValue {
  9. unsigned int key;
  10. const char* value;
  11. } KeyValue;
  12. void set_key_values(KeyValue * const new_key_values,
  13. const unsigned int new_number_of_key_values);
  14. extern KeyValue* find_item_by_value(const char * const value);
  15. extern void sort_items_by_key();
  16. static KeyValue key_values[] = {
  17. { 10, "this" },
  18. { 52, "test" },
  19. { 20, "a" },
  20. { 13, "is" },
  21. };
  22. void create_key_values(void **state) {
  23. KeyValue * const items = (KeyValue*)test_malloc(sizeof(key_values));
  24. memcpy(items, key_values, sizeof(key_values));
  25. *state = (void*)items;
  26. set_key_values(items, sizeof(key_values) / sizeof(key_values[0]));
  27. }
  28. void destroy_key_values(void **state) {
  29. test_free(*state);
  30. set_key_values(NULL, 0);
  31. }
  32. void test_find_item_by_value(void **state) {
  33. unsigned int i;
  34. for (i = 0; i < sizeof(key_values) / sizeof(key_values[0]); i++) {
  35. KeyValue * const found = find_item_by_value(key_values[i].value);
  36. assert_true(found);
  37. assert_int_equal(found->key, key_values[i].key);
  38. assert_string_equal(found->value, key_values[i].value);
  39. }
  40. }
  41. void test_sort_items_by_key(void **state) {
  42. unsigned int i;
  43. KeyValue * const kv = *state;
  44. sort_items_by_key();
  45. for (i = 1; i < sizeof(key_values) / sizeof(key_values[0]); i++) {
  46. assert_true(kv[i - 1].key < kv[i].key);
  47. }
  48. }
  49. int main(int argc, char* argv[]) {
  50. const UnitTest tests[] = {
  51. unit_test_setup_teardown(test_find_item_by_value, create_key_values,
  52. destroy_key_values),
  53. unit_test_setup_teardown(test_sort_items_by_key, create_key_values,
  54. destroy_key_values),
  55. };
  56. return run_tests(tests);
  57. }
该文件里面声明了一组测试用的键值对数组
  1. static KeyValue key_values[] = {
  2. { 10, "this" },
  3. { 52, "test" },
  4. { 20, "a" },
  5. { 13, "is" },
  6. };

create_key_values使用这组测试的数据,赋值了一个键值对集合,调用set_key_values赋值到全局静态变量里,进行测试前的准备
destroy_key_values释放create_key_values函数中申请的内存并且将全局静态变量设置为0
test_find_item_by_value函数里使用assert函数对于从全局静态变量里面查找到的值与上面的测试键值对组的值挨个进行比较,以确认能够正常的找到
test_sort_items_by_key函数会使用sort_items_by_key函数将这个上面的键值对组进行排序,然后挨个比较确认排序是成功的。

在main函数里面向UnitTest数组进行注册单元测试的时候使用的unit_test_setup_teardown这个函数,实际上这个是一个宏定义如下:
  1. // 初始化一个单元测试结构体.
  2. #define unit_test(f) { #f, f, UNIT_TEST_FUNCTION_TYPE_TEST }
  3. #define unit_test_setup(test, setup) \
  4. { #test "_" #setup, setup, UNIT_TEST_FUNCTION_TYPE_SETUP }
  5. #define unit_test_teardown(test, teardown) \
  6. { #test "_" #teardown, teardown, UNIT_TEST_FUNCTION_TYPE_TEARDOWN }
  7. /* Initialize an array of UnitTest structures with a setup function for a test
  8. * and a teardown function. Either setup or teardown can be NULL.
  9. */
  10. #define unit_test_setup_teardown(test, setup, teardown) \
  11. unit_test_setup(test, setup), \
  12. unit_test(test), \
  13. unit_test_teardown(test, teardown)
即分别调用了unit_test_setup,unit_test,unit_test_teardown三个宏进行展开成为UnitTest的三个成员,且他们的类型也都做了赋值。
两个测试单元分别测试了上面的两个函数:test_find_item_by_value,test_sort_items_by_key。

在这里使用unit_test_setup_teardown将每一组setup test teardown进行注册进去就是为了保证其执行的先后顺序。实际上就是在UnitTest按照顺序初始化了值。然后再执行run_tests函数的时候就是按照UnitTest数组里面的顺序进行执行的。借助于assert类函数,保证测试的目的可以达到。

最终的执行结果如下:





posted on 2017-08-28 11:53  cfzhang  阅读(497)  评论(0编辑  收藏  举报

导航