为一个咨询项目做准备,学习了几种对C语言函数进行mock的方法,由于C语言面向过程, 缺乏封装,继承,多态等面向对象语言的特性, 也无法利用面向对象中多态这个特性来实现mock,相对来说比java等OO的语言难于测试。 但也不是没有办法,先看例子:
下面的代码中account_update函数使用了db_update这个函数,它会直接调用数据库,是个重量级的依赖。 为了对这段代码进行测试, 需要把db_update函数隔离,怎么处理?
#include <DFHLItem.h>
#include <DHLSRecord.h>
extern int db_update(int, struct DFHLItem *);
void account_update(
int account_no, struct DHLSRecord *record, int activated)
{
if (activated) {
if (record->dateStamped && record->quantity > MAX_ITEMS) {
db_update(account_no, record->item);
} else {
db_update(account_no, record->backup_item);
}
}
db_update(MASTER_ACCOUNT, record->item);
}
方法一:利用C语言的预处理(在编译之前进行Mock)
先引入一个头文件:
#include <DFHLItem.h>
#include <DHLSRecord.h>
extern int db_update(int, struct DFHLItem *);
#include "localdefs.h"
void account_update(
int account_no, struct DHLSRecord *record, int activated)
{
if (activated) {
if (record->dateStamped && record->quantity > MAX_ITEMS) {
db_update(account_no, record->item);
} else {
db_update(account_no, record->backup_item);
}
}
db_update(MASTER_ACCOUNT, record->item);
}
在该头文件中提供一个db_update的定义,注意,使用了#define把db_update展开为一段代码
#ifdef TESTING
...
struct DFHLItem *last_item = NULL;
int last_account_no = -1;
#define db_update(account_no,item)\
{last_item = (item); last_account_no = (account_no);}
...
#endif
这样C语言编译器可以把所有的db_update都替换成{last_item = (item); last_account_no = (account_no);}, 这段代码会记录下最后的item和account_no,可以供测试中的验证使用
使用宏就会丢失类型安全,如果逻辑复杂的话,很容易出错谨慎使用该方法。
方法二: 使用函数指针(编译期进行mock)
(1)首先写一个函数指针: int (*db_update)(int, struct DFHLItem *)
(2)把原来的db_update 改名为 int db_update_production(int, struct DFHLITem *)
(3) 编写一个mock实现 int db_update_mock(int, struct DFHLITem *)
(4) 最后使用条件编译来制定到底用哪个函数
#ifdef TESTING
db_update = db_update_mock
#else
db_update = db_update_production
#endif
该方法很灵活, 可以随意通过函数指针进行替换,还能兼顾类型安全 ,推荐使用。
方法三: 在编译之后 Link时候进行替换
这就需要编写包括db_update的库函数,在link的时候使用这个假的库函数。 当然Link出来的exe文件指示一个测试版本。
如果需要函数很多, 还有db_insert, db_delete等等, 这些函数都需要在假的库函数中进行实现, 开销不小。
看过《修改代码的艺术》这本书的人可能对上面的例子有些眼熟,不错,上面的方法和例子就是从这本书中来的。
这本书对于处理遗留代码提供了大量的方法,强烈推荐阅读!
分享到:
相关推荐
可以用来Mock JAVA代码中的静态方法
1、应用UNIX的fork()等系统调用,编写一个c程序具有以下功能: a) 实现Shell的基本功能,包括有:打印提示符; 接受和分析命令行(滤去无效的空格、tab符号以及换行符等);执行命令(要有出错处理;...
这只是一组标题,提供了一种在测试中将工具用于具有模拟功能的模拟方法的方法。 C Mock并非旨在促进不良设计。 其目标是帮助开发人员测试其代码。 在使用C Mock之前,建议阅读以下内容: 要求 Google测试...
django-mock-queries, 在测试内存中,用于模拟 Django queryset函数的库 Django 模拟查询模拟内存中 Django queryset函数的库特性方法链接的QuerySet风格支持使用Q 对象过滤聚合生成CRUD函数字段查找django-rest-...
PHP-Mock - 一个模拟内置PHP函数的库(比如:time(), exec() or rand())
NULL 博文链接:https://never-forget.iteye.com/blog/1717297
Classes contained in spring-mock.jar: org.springframework.mock.jndi.ExpectedLookupTemplate.class org.springframework.mock.jndi.SimpleNamingContext.class org.springframework.mock.jndi....
在java web应用中,进行用例实现时,很多情况难以模拟,比如数据库用例,如果直接通过连接数据库进行测试,导致用例对环境依赖很大,这时,可以通过mock技术可以模拟构造数据环境,从而进行单元测试,这里提供有实现...
mock练习
go-mock是专门为go语言开发的mock库,该库使用方式简单,支持自动生成代码,这篇文章主要介绍了用gomock进行mock测试的方法示例,感兴趣的小伙伴们可以参考一下
本项目还提供了一个快速搭建本地 mock 服务的解决方案。技术栈 Taro + Taro UI + Redux + Webpack + ES6 + Mock 目录 项目简介 技术栈 项目截图 目录 运行项目 开始学习 Taro 简介 开发工具 样式规范 CSS 预处理器 ...
mock 介绍及原理,前后端 mock方法
mock3.json
支持http接口自由mock,可根据需要进行接口mock测试。
Spring针对J2EE的常用Web接口提供了Mock,这些组件被发布于spring-mock.jar,介绍如下: MockHttpServletRequest:HttpServletRequest接口的mock实现。 MockHttpServletResponse:HttpServletResponse接口的mock...
mock
简单的mockServer、模拟后台生成数据、启动后像后台一样直接调用接口
php-mock, PHP函数( 比如,模拟生成 时间( ),exec() 或者 rand() PHP模拟:用PHP函数构建的模拟PHP mock是一个测试库,它模仿了 time() 或者 rand() 之类的不确定的PHP函数。 这是由php回退策略插件的命名...
模块化配置mock,结合mock-api,axios,可应用于实际项目中;前后端分离开发之后,有了mock就可以不用等后端的接口完成后调用接口,前端可以自行模拟接口数据,快速开发。