近两天一有空就会去看看项目代码,思考一下如何利用cmockery对项目里已有的代码进行测试。项目代码中很多被调用的接口都带有输出参数,而且在这些接口中多利用返回值指示执行成败也否,而利用输出参数返回一些关键结果,这些结果值甚至影响着后续的函数执行流程。前期研究cmockery时没有注意到cmockery是否可以设置被mock接口的输出参数的值,不过回顾了一下cmockery实现的原理,觉得cmockery是应该可以支持的。遂重新翻看了一下cmockery的manual,发现在mock_query_database中确有对输出参数的mock调用,代码如下:
// Mock query database function.
unsigned int mock_query_database( DatabaseConnection* const connection,
const char * const query_string, void *** const results)
{
*results = (void**)mock();
return (unsigned int)mock();
}
void test_get_customer_id_by_name(void **state) {
DatabaseConnection connection = { "somedatabase.somewhere.com", 12345678, mock_query_database };
int customer_ids = 543;
will_return(mock_query_database, &customer_ids);
will_return(mock_query_database, 1);
assert_int_equal(get_customer_id_by_name(&connection, "john doe"), 543);
}
上面代码在test_get_customer_id_by_name中两次针对被mock的接口mock_query_database调用will_return,实际上是在符号“mock_query_database”对应的value list里插入了两个item,第一个item的值为&customer_ids,第二个为1。当测试执行到mock_query_database的第一个mock时,返回第一个item:&customer_ids,执行到第二个mock时返回第二个item的值1。这样在测试过程中设置输出参数值的目的就达到了。
在使用cmockery时唯一需要你关注的就是will_return设置的顺序和在被mock接口中调用mock的顺序,切记不要弄反了。
这里再举一个例子,再直观感受一下:
/* message_handler.c */
#include
extern int dispatch_message(void *msg);
extern int get_next_message(void **msg);
int handle_next_message() {
void * temp_msg = NULL;
int rv = 0;
rv = get_next_message(&temp_msg);
if (!rv) {
if (!temp_msg) {
return -1;
} else {
return dispatch_message(temp_msg);
}
}
return rv;
}
/* test_message_handler.c */
#include
#include
#include
#include "cmockery.h"
#include
int dispatch_message(void *msg) {
return 0;
}
int get_next_message(void **msg) {
(*msg) = (void*)mock();
return (int)mock();
}
extern int handle_next_message();
void test_handle_next_message_success(void **state) {
will_return(get_next_message, 0×1234);
will_return(get_next_message, 0);
assert_true(handle_next_message() == 0);
}
void test_handle_next_message_fail(void **state) {
will_return(get_next_message, NULL);
will_return(get_next_message, 0);
assert_true(handle_next_message() == -1);
}
int main() {
const UnitTest tests[] = {
unit_test(test_handle_next_message_success),
unit_test(test_handle_next_message_fail)
};
return run_tests(tests);
}
执行结果:
test_handle_next_message_success: Starting test
test_handle_next_message_success: Test completed successfully.
test_handle_next_message_fail: Starting test
test_handle_next_message_fail: Test completed successfully.
All 2 tests passed
评论