Skip to content
Tony Bai edited this page Sep 16, 2013 · 2 revisions

Table of Contents

简介

lcutLightweight C Unit Test framework的缩写,它使用标准C语言实现,可以很容易的在不同额主流平台上使用,如Solaris、Linux等。

测试执行

一个使用lcut进行的单元测试有三个层次:一个逻辑测试、测试套件和测试用例。每个逻辑测试可以包含多个测试套件,且每个测试套件又包含多个测试用例。在lcut这个测试框架中,测试用例是最基本和最小的单元。

实际上,lcut中的测试用例是原型为

void (*tc_func)(lcut_tc_t *tc, void *data)
的函数。lcut使用 LCUT_TC_ADD 宏向一个测试套件中添加一个测试用例,测试套件使用 LCUT_TS_INIT 宏初始化。每个使用lcut进行的单元测试开始于 LCUT_TEST_BEGIN,结束于 LCUT_TEST_END 。另外 LCUT_TEST_RESULT宏可用于将执行结果反馈给本次测试的调用者(例如一些持续集成脚本等)。
#include "lcut.h"

/*
 * A case that test nothing
 */
void tc_trivial_test(lcut_tc_t *tc, void *data) {

}

int main() {
    lcut_ts_t   *suite = NULL;
    LCUT_TEST_BEGIN("A Trivial test", NULL, NULL);

    LCUT_TS_INIT(suite, "A Trivial test suite", NULL, NULL);
    LCUT_TC_ADD(suite, "A Trivial test case", tc_trivial_test, NULL, NULL, NULL);
    LCUT_TS_ADD(suite);

    LCUT_TEST_RUN();
    LCUT_TEST_REPORT();
    LCUT_TEST_END();

    LCUT_TEST_RESULT();
}

上面测试输出结果如下:

*********************************************************
	LCUT -- Lightweight C Unit Testing framework
 		 By Tony Bai
********************************************************* 
Unit Test for 'A Trivial test':

	Suite <A Trivial test suite>: 
		Case 'A Trivial test case': Passed

Summary: 
	Total Suites: 1 
	Failed Suites: 0 
	Total Cases: 1 
	Failed Cases: 0 


==========================

	GREEN BAR!

==========================

如果所有测试用例都通过,则你的控制台上会输出一个绿色的"GREEN BAR!",否则红色的"RED BAR!"将被呈现出来,并且伴随着失败用例的原因,例如:

Unit Test for 'A Trivial test':

	Suite <A Trivial test suite>: 
		Case 'A Trivial test case': Failure occur in tc_null_test, 23 line in file runtests.c, expected<1> : actual<2>

Summary: 
	Total Suites: 1 
	Failed Suites: 0 
	Total Cases: 1 
	Failed Cases: 0 


==========================

	RED BAR!

==========================

断言

lcut提供了许多断言宏:

  * LCUT_INT_EQUAL(tc, expected, actual)
  * LCUT_INT_NEQUAL(tc, expected, actual)
  * LCUT_STR_EQUAL(tc, expected, actual)
  * LCUT_STR_NEQUAL(tc, expected, actual)
  * LCUT_ASSERT(tc, msg, condition)
  * LCUT_TRUE(tc, condition)

断言宏的使用方法显而易见,这里不赘述。

Mock支持

lcut支持mock,mock是一种重要的将你的单元测试与外部依赖隔离的方法。 LCUT_MOCK_RETV 和 LCUT_MOCK_ARG 分别用例mock函数的返回值和输出参数。

Mocked函数 'table_row_count' 实现如下:

int table_row_count(const database_conn *conn,
                    const char *table_name,
                    int *total_count) {
    (*total_count) = (int)LCUT_MOCK_ARG();
    return (int)LCUT_MOCK_RETV();
}
<pre>

依赖'table_row_count'的测试用例可以使用被mocked的'table_row_count'函数,并且可通过 LCUT_RETV_RETURN 和 LCUT_ARG_RETURN 宏来自由控制被mocked的'table_row_count'的返回值和输出参数的值。

<pre>
    LCUT_ARG_RETURN(table_row_count, 5);  /* the total_count will be 5 after invoking the mocked table_row_count */
    LCUT_RETV_RETURN(table_row_count, 0); /* the return value of mocked table_row_count will be 0 */

lcut还提供了两个宏 LCUT_ARG_RETURN_COUNT 和 LCUT_RETV_RETURN_COUNT ,用于被测试接口多次调用mocked接口的情况:

例如:
int bar(int *outparameter) {
   ...
   foo();

   ...
   foo();

   ...
   foo();
}

如果要对bar进行测试,我们需要对foo进行mock,由于bar调用了三次foo,使用常规接口我们需要调用三次 LCUT_RETV_RETURN 和 LCUT_ARG_RETURN 对mocked foo进行相关设置,这里若使用 LCUT_ARG_RETURN_COUNT 和 LCUT_RETV_RETURN_COUNT 则只需调用一次,例如:

/* in some test case */
  LCUT_RETV_RETURN_COUNT(foo, 13, 3);
  LCUT_ARG_RETURN_COUNT(foo, 17, 3);

如果希望某个被mocked的函数一直返回某个相同的值,可以将最后一个参数count设置为-1传入,例如:

LCUT_RETV_RETURN_COUNT(foo, 13, -1);/* make foo always return 13 */
LCUT_ARG_RETURN_COUNT(foo, 17, -1); /* make foo's outparameter always evaluated to 17 */

这样无论调用几次foo,其返回值都为13,其输出参数都为17。

跟过关于mock支持的细节可参考lcut包中example目录下的例子。

注意 : lcut不支持mock类型为double的函数返回值或参数。

Clone this wiki locally