首 页 » 程序开发 » C语言单元测试框架比较

C语言单元测试框架比较

[ 2017-02-19 19:00 | 浏览次数: 1,204次 | 0条评论 ]

最新想在嵌入式里做一些UT,所以找了一些UT框架评估,寻求理想中的框架

特性比较

名称 文件 无需动态内存 筛选 suite set up&tear down star Fork
fctx 1 23 11
zCUT 4 0 1
Unity 3 521 208
cmockery 2 180 111
cheat 2 ? 123 6
greatest 1 847 65
minunit 1 147 34
cutest 2 8 12

注:

  1. zCUT只支持Linux平台,但是唯一一个支持通配符筛选的
  2. star表示在github上的star数
  3. Fork表示在github上的fork数
  4. 表中文件表示文件数量,筛选表示是否支持筛选case
  5. suite表示是否支持suite
  6. cutest
  7. minunit
  8. greatest
  9. cheat
  10. cmockery
  11. fctx
  12. zCUT
  13. Unity

使用例

fctx

  /* Now lets define our testing scope. */
  FCT_BGN()
  {
     /* A simple test case. No setup/teardown. */
     FCT_SUITE_BGN(simple)
     {
        /* An actual test case in the test suite. */
        FCT_TEST_BGN(strcmp_eq)
        {
           fct_chk(strcmp("durka", "durka") == 0);
        }
        FCT_TEST_END();

        FCT_TEST_BGN(chk_neq)
        {
           fct_chk(strcmp("daka", "durka") !=0 );
        }
        FCT_TEST_END();

     /* Every test suite must be closed. */
     }
     FCT_SUITE_END();   

  /* Every FCT scope has an end. */
  }
  FCT_END();

zCUT

#include <zcut.h>

TEST_CASE(test_case_name0)
{
    ...     /* Test body, assertion are here. */
}
TEST_CASE(test_case_name1)
{
    ...
}

TEST_SUITE(test_suite_name0)
{
    test_case_name0,
    test_case_name1,
    TEST_NULL
};

TEST_RUNNER(test_runner_name)
{
    test_suite_name0,
    TEST_NULL
};

Unity

void setUp(void)
{
  /* This is run before EACH TEST */
  Counter = 0x5a5a;
}

void tearDown(void)
{
}

void test_FindFunction_WhichIsBroken_ShouldReturnZeroIfItemIsNotInList_WhichWorksEvenInOurBrokenCode(void)
{
  /* All of these should pass */
  TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(78));
  TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(1));
  TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(33));
  TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(999));
  TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(-1));
}

void test_FindFunction_WhichIsBroken_ShouldReturnTheIndexForItemsInList_WhichWillFailBecauseOurFunctionUnderTestIsBroken(void)
{
  /* You should see this line fail in your test summary */
  TEST_ASSERT_EQUAL(1, FindFunction_WhichIsBroken(34));

  /* Notice the rest of these didn't get a chance to run because the line above failed.  
   * Unit tests abort each test function on the first sign of trouble. 
   * Then NEXT test function runs as normal. */
  TEST_ASSERT_EQUAL(8, FindFunction_WhichIsBroken(8888));
}

void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValue(void)
{
    /* This should be true because setUp set this up for us before this test */
    TEST_ASSERT_EQUAL_HEX(0x5a5a, FunctionWhichReturnsLocalVariable());

    /* This should be true because we can still change our answer */
    Counter = 0x1234;
    TEST_ASSERT_EQUAL_HEX(0x1234, FunctionWhichReturnsLocalVariable());
}

void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValueAgain(void)
{
    /* This should be true again because setup was rerun before this test (and after we changed it to 0x1234) */
    TEST_ASSERT_EQUAL_HEX(0x5a5a, FunctionWhichReturnsLocalVariable());
}

void test_FunctionWhichReturnsLocalVariable_ShouldReturnCurrentCounter_ButFailsBecauseThisTestIsActuallyFlawed(void)
{
    /* Sometimes you get the test wrong.  When that happens, you get a failure too... and a quick look should tell
     * you what actually happened...which in this case was a failure to setup the initial condition. */
    TEST_ASSERT_EQUAL_HEX(0x1234, FunctionWhichReturnsLocalVariable());
}

int main(void)
{
  UnityBegin("test/TestProductionCode.");
  RUN_TEST(test_FindFunction_WhichIsBroken_ShouldReturnZeroIfItemIsNotInList_WhichWorksEvenInOurBrokenCode, 20);
  RUN_TEST(test_FindFunction_WhichIsBroken_ShouldReturnTheIndexForItemsInList_WhichWillFailBecauseOurFunctionUnderTestIsBroken, 30);
  RUN_TEST(test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValue, 41);
  RUN_TEST(test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValueAgain, 51);
  RUN_TEST(test_FunctionWhichReturnsLocalVariable_ShouldReturnCurrentCounter_ButFailsBecauseThisTestIsActuallyFlawed, 57);

  return (UnityEnd());
}

cmockery

// Ensure main() in example.c succeeds given no arguments.
void test_example_main_no_args(void **state) {
    char *args[] = {
        "example",
    };
    assert_int_equal(example_main(array_length(args), args), 0);
}

// Ensure main() in example.c succeeds given valid input arguments.
void test_example_main(void **state) {
    char *args[] = {
        "example", "1", "+", "3", "*", "10",
    };

    expect_string(example_test_printf, temporary_buffer, "1\n");
    expect_string(example_test_printf, temporary_buffer, "  + 3 = 4\n");
    expect_string(example_test_printf, temporary_buffer, "  * 10 = 40\n");
    expect_string(example_test_printf, temporary_buffer, "= 40\n");

    assert_int_equal(example_main(array_length(args), args), 0);
}

int main(int argc, char* argv[]) {
    UnitTest tests[] = {
        unit_test(test_example_main_no_args),
        unit_test(test_example_main),
    };
    return run_tests(tests);
}

cheat

CHEAT_DECLARE(
    static char const yes[] = "yes";
    static char const times = '*';
    static int const thirteen = 13;
    static char const equals = '=';
    static double const a_lot = 1.21e+9;
)

CHEAT_TEST(confusing,
    cheat_assert(times == thirteen);
    cheat_assert(&equals == (char* )0xdead);
    cheat_assert(sizeof *yes != sizeof times);
)

greatest

#include "greatest.h"

/* A test runs various assertions, then calls PASS(), FAIL(), or SKIP(). */
TEST x_should_equal_1(void) {
    int x = 1;
    ASSERT_EQ(1, x);                              /* default message */
    ASSERT_EQm("yikes, x doesn't equal 1", 1, x); /* custom message */
    /* printf expected and actual values as "%d" if they differ */
    ASSERT_EQ_FMT(1, x, "%d");
    PASS();
}

/* Suites can group multiple tests with common setup. */
SUITE(the_suite) {
    RUN_TEST(x_should_equal_1);
}

/* Add definitions that need to be in the test runner's main file. */
GREATEST_MAIN_DEFS();

int main(int argc, char **argv) {
    GREATEST_MAIN_BEGIN();      /* command-line arguments, initialization. */

    /* Individual tests can be run directly. */
    /* RUN_TEST(x_should_equal_1); */

    /* Tests can also be gathered into test suites. */
    RUN_SUITE(the_suite);

    GREATEST_MAIN_END();        /* display results */
}

minunit

    #include "minunit.h"

    MU_TEST(test_check) {
        mu_check(5 == 7);
    }
    MU_TEST_SUITE(test_suite) {
        MU_RUN_TEST(test_check);
    }

    int main(int argc, char *argv[]) {
        MU_RUN_SUITE(test_suite);
        MU_REPORT();
        return 0;
    }

cutest

   #include "CuTest.h"

    char* StrToUpper(char* str) {
        return str;
    }

    void TestStrToUpper(CuTest *tc) {
        char* input = strdup("hello world");
        char* actual = StrToUpper(input);
        char* expected = "HELLO WORLD";
        CuAssertStrEquals(tc, expected, actual);
    }

    CuSuite* StrUtilGetSuite() {
        CuSuite* suite = CuSuiteNew();
        SUITE_ADD_TEST(suite, TestStrToUpper);
        return suite;
    }

//Create another file called AllTests.c with these contents:

    #include "CuTest.h"

    CuSuite* StrUtilGetSuite();

    void RunAllTests(void) {
        CuString *output = CuStringNew();
        CuSuite* suite = CuSuiteNew();

        CuSuiteAddSuite(suite, StrUtilGetSuite());

        CuSuiteRun(suite);
        CuSuiteSummary(suite, output);
        CuSuiteDetails(suite, output);
        printf("%s\n", output->buffer);
    }

    int main(void) {
        RunAllTests();
    }
您可以任意转载本文,但转载时请勿删除作者信息。
作者:hgyxbll,原文链接:http://shashanzhao.com/archives/1188.html
上一篇: | 下一篇:

沙发为空,还不快枪?[点此发言]

目前还没有任何评论.