5

我正在开发一个使用 cmocka 框架的项目。cmocka主页状态

测试夹具是设置和拆卸功能,可以在多个测试用例之间共享,以提供准备测试环境并在之后销毁它的通用功能。

但是,读过的所有文档 都没有解释夹具系统的工作原理。

如果我使用看起来像这样的代码运行我的测试

int main(void) {
  const struct CMUnitTest license_tests[] = {
      cmocka_unit_test(test_setup),                        
      cmocka_unit_test(test_null_app),      
      cmocka_unit_test(test_null_name),        
  };

  return cmocka_run_group_tests(license_tests, NULL, NULL);
}

我如何/在哪里可以指示 cmocka 运行设置/拆除固定装置以及 cmocka 有哪些功能(如果有)可以让我访问在所述固定装置中创建的东西?

4

2 回答 2

9

这是一个可以在项目中重复使用的模板单元测试文件。它可以满足您的所有要求

#include <stdio.h>
#include <cmocka.h>

#include "mylib.h"

// Include here all your mocked functions, see below
#include "testmocks.c"

typedef struct {
  mylibobj_t* mylibobj;
} teststate_t;

/**
 * This is run once before all group tests
 */
static int groupSetup (void** state) {
  teststate_t* teststate = calloc(1, sizeof(teststate_t));    
  *state = teststate;
  return 0;
}

/**
 * This is run once after all group tests
 */
static int groupTeardown (void** state) {
  teststate_t* teststate = *state;
  free(teststate);
  return 0;
}

/**
 * This is run once before one given test
 */
static int testSetup (void** state) {
  teststate_t* teststate = *state;
  //Maybe instantiate mylibobj?
  return 0;
}

/**
 * This is run once after one given test
 */
static int testTeardown (void** state) {
  return 0;
}

/**
 * This test will success with these options
 */
void mylib_setTime_s0 (void** state) {
  teststate_t* teststate = *state;
  // Do your testing stuff
}

/**
 * This test will fail with these options
 */
void mylib_setTime_f0 (void** state) {
  teststate_t* teststate = *state;
  // Do your testing stuff
}

int main (void) {
  const struct CMUnitTest tests[] = {
    cmocka_unit_test_setup_teardown(mylib_setTime_s0, testSetup, testTeardown),
    cmocka_unit_test_setup_teardown(mylib_setTime_f0, testSetup, testTeardown),
  };
  return cmocka_run_group_tests(tests, groupSetup, groupTeardown);
}

testmocks.c 仅用于代码组织,并且可能包含 0 到 N 对模拟函数

#define MOCKBYPASS  -7337

mylib_status_t __real_inner_function (char* id);
mylib_status_t __wrap_inner_function (char* id) {
  int mock = mock();
  if(mock == MOCKBYPASS)
    return __real_inner_function(id);
  else
    return mock;
}

...

请记住,gcc 编译技巧是这些模拟正确工作的必要条件

于 2018-05-17T14:02:46.523 回答
3

你传递给cmocka_run_group_tests函数的那两个 NULL 应该是函数group_setupgroup_teardown两者都是类型CMFixtureFunction- 如果你想利用

可以跨多个测试用例共享的设置和拆卸功能

在 cmocka 中称为测试夹具。作为此功能的文档状态。

然后在每个测试中都可以访问shared (void** state) 。它可以像下面的例子一样使用:

#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <cmocka.h>

#define GREETINGS "one string to rule them all, One string to find them, "\
                  "one string to bring them all and in the darkness bind them"
#define PRECIOUSS_T1 "Three strings for the Elven-kings under the sky,"
#define PRECIOUSS_T2 "even for the Dwarf-lords in halls of stone,"
#define PRECIOUSS_T3 "Nine for Mortal Men, doomed to die,"
#define PRECIOUSS_T4 "One for the Dark Lord on his dark throne"
#define PRECIOUSS_T5 "In the Land of Mordor where the Shadows lie."
#define PRECIOUSS_T6 "One string to rule them all, One Ring to find them,"
#define PRECIOUSS_T7 "One string to bring them all and in the darkness bind them."
#define PRECIOUSS_T8 "In the Land of Mordor where the Shadows lie."
#define OOPS "Not quite what I expected"
#define T(X) PRECIOUSS_T##X

#define FOO(X) case X: strncpy(lots->memory, T(X), sizeof(T(X))); break;
#define SPR_FOO(X) case X: assert_string_equal(T(X), lots->memory); break;

typedef struct {
          int    line;
          char * memory;
} lord_of_the_strings_t;

static int gr_setup(void **state) {
     /* this is run once before all group tests */
     lord_of_the_strings_t *book = malloc(sizeof(*book));
     if (book == NULL)
         return -1;
     book->memory = malloc(sizeof(GREETINGS));
     if (book->memory == NULL) {
         return -1;
     }

     strncpy(book->memory, GREETINGS, sizeof(GREETINGS));
     assert_string_equal(book->memory, GREETINGS);
     *state = book;
     return 0;
}

static int gr_teardown(void **state) {
     /* this is run once after all group tests */
     lord_of_the_strings_t *lots = *state;
     free(lots->memory);
     free(lots);
     return 0;
}

static int ve_teardown(void **state) {
     /* this is run before some single tests */
     lord_of_the_strings_t *lots = *state;
     lots->line = 42;
     return 0;
}

static int ve_setup(void **state) {
     /* this is run after some single tests */
     static int setup_counter = 0;
     lord_of_the_strings_t *lots = *state;
     lots->line = ++setup_counter;
     switch (setup_counter) {
        FOO(1)
        FOO(2)
        FOO(3)
        FOO(4)
        FOO(5)
        FOO(6)
        FOO(7)
        FOO(8)
        default:
           strncpy(lots->memory, OOPS, sizeof(OOPS));
     };
     return 0;
}

static void failing_test(void **state) {
     assert_false("Sorry");
}

static void line_aware_test(void **state) {
     lord_of_the_strings_t *lots = *state;
     printf("             (shared) between tests, line=%d memory=%s\n", lots->line, lots->memory);
}

static void passing_test(void **state) {
}
static void string_recite_test(void **state) {
     static int line_counter = 0;
     lord_of_the_strings_t *lots = *state;
     if (lots->line < 9)
        assert_true(line_counter+1 == lots->line);
     switch (++line_counter) {
        SPR_FOO(1)
        SPR_FOO(2)
        SPR_FOO(3)
        SPR_FOO(4)
        SPR_FOO(5)
        SPR_FOO(6)
        SPR_FOO(7)
        SPR_FOO(8)
        default:
            line_counter = 0;
     }
}


int main(void) {
        const struct CMUnitTest tests[] = {
            cmocka_unit_test(passing_test),
            cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
            cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
            cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
            cmocka_unit_test(line_aware_test),
            cmocka_unit_test(line_aware_test),
            cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
            cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
            cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
            cmocka_unit_test(line_aware_test),
            cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
            cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
            cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
            cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
            cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
            cmocka_unit_test(line_aware_test),
            cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
            cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
            cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
            cmocka_unit_test_setup_teardown(string_recite_test, ve_setup, ve_teardown),
            cmocka_unit_test(failing_test),
        };
        return cmocka_run_group_tests(tests, gr_setup, gr_teardown);
}

哪个应该产生像

[==========] Running 21 test(s).
[ RUN      ] passing_test
[       OK ] passing_test
[ RUN      ] string_recite_test
[       OK ] string_recite_test
[ RUN      ] string_recite_test
[       OK ] string_recite_test
[ RUN      ] string_recite_test
[       OK ] string_recite_test
[ RUN      ] line_aware_test
             (shared) between tests, line=42 memory=Nine for Mortal Men, doomed to die,
[       OK ] line_aware_test
[ RUN      ] line_aware_test
             (shared) between tests, line=42 memory=Nine for Mortal Men, doomed to die,
[       OK ] line_aware_test
[ RUN      ] string_recite_test
[       OK ] string_recite_test
[ RUN      ] string_recite_test
[       OK ] string_recite_test
[ RUN      ] string_recite_test
[       OK ] string_recite_test
[ RUN      ] line_aware_test
             (shared) between tests, line=42 memory=One string to rule them all, One Ring to find them,
[       OK ] line_aware_test
[ RUN      ] string_recite_test
[       OK ] string_recite_test
[ RUN      ] string_recite_test
[       OK ] string_recite_test
[ RUN      ] string_recite_test
[       OK ] string_recite_test
[ RUN      ] string_recite_test
[  ERROR   ] --- "Three strings for the Elven-kings under the sky," != "Not quite what I expected"
[   LINE   ] --- aa.c:100: error: Failure!
[  FAILED  ] string_recite_test
[ RUN      ] string_recite_test
[  ERROR   ] --- "even for the Dwarf-lords in halls of stone," != "Not quite what I expected"
[   LINE   ] --- aa.c:101: error: Failure!
[  FAILED  ] string_recite_test
[ RUN      ] line_aware_test
             (shared) between tests, line=42 memory=Not quite what I expected
[       OK ] line_aware_test
[ RUN      ] string_recite_test
[  ERROR   ] --- "Nine for Mortal Men, doomed to die," != "Not quite what I expected"
[   LINE   ] --- aa.c:102: error: Failure!
[  FAILED  ] string_recite_test
[ RUN      ] string_recite_test
[  ERROR   ] --- "One for the Dark Lord on his dark throne" != "Not quite what I expected"
[   LINE   ] --- aa.c:103: error: Failure!
[  FAILED  ] string_recite_test
[ RUN      ] string_recite_test
[  ERROR   ] --- "In the Land of Mordor where the Shadows lie." != "Not quite what I expected"
[   LINE   ] --- aa.c:104: error: Failure!
[  FAILED  ] string_recite_test
[ RUN      ] string_recite_test
[  ERROR   ] --- "One string to rule them all, One Ring to find them," != "Not quite what I expected"
[   LINE   ] --- aa.c:105: error: Failure!
[  FAILED  ] string_recite_test
[ RUN      ] failing_test
[  ERROR   ] --- "Sorry"
[   LINE   ] --- aa.c:79: error: Failure!
[  FAILED  ] failing_test
[==========] 21 test(s) run.
[  PASSED  ] 14 test(s).
[  FAILED  ] 7 test(s), listed below:
[  FAILED  ] string_recite_test
[  FAILED  ] string_recite_test
[  FAILED  ] string_recite_test
[  FAILED  ] string_recite_test
[  FAILED  ] string_recite_test
[  FAILED  ] string_recite_test
[  FAILED  ] failing_test

 7 FAILED TEST(S)
于 2017-11-11T23:04:15.080 回答