打桩是一种用定制的函数替换链接库函数且不需重新编译的技术。甚至可用此技术替换系统调用(更确切地说,库函数包装系统调用)。可能的应用是沙盒、调试或性能优化库。为演示过程,此处给出一个简单库,以记录GNU/Linux中
malloc 调用次数。
/* _GNU_SOURCE is needed for RTLD_NEXT, GCC will not define it by default */#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <stdint.h>
#include <inttypes.h>
staticuint32_t malloc_count = 0
staticuint64_t total = 0
voidsummary(){
fprintf(stderr, "malloc called: %u times\n", count)
fprintf(stderr, "total allocated memory: %" PRIu64 " bytes\n", total)
}
void*malloc(size_tsize){
staticvoid* (*real_malloc)(size_t) = NULL
void*ptr = 0
if(real_malloc == NULL){
real_malloc = dlsym(RTLD_NEXT, "malloc")
atexit(summary)
}
count++
total += size
returnreal_malloc(size)
}
打桩要在链接libc.so之前加载此库,这样我们的 malloc 实现就会在二进制文件执行时被链接。可通过设置 LD_PRELOAD
环境变量为我们想让链接器优先链接的全路径。这也能确保其他动态链接库的调用最终使用我们的 malloc
实现。因为我们的目标只是记录调用次数,不是真正地实现内存分配,所以我们仍需要调用“真正”的 malloc 。通过传递 RTLD_NEXT 伪处理程序到
dlsym,我们获得了指向下一个已加载的链接库中 malloc 事件的指针。第一次 malloc 调用 libc 的 malloc,当程序终止时,会调用由
atexit 注册的获取和 summary 函数。看GNU/Linxu中打桩行为(真的184次调用!):
$ gcc -shared -ldl -fPIC malloc_counter.c -o /tmp/libmcnt.so$ export LD_PRELOAD="/tmp/libstr.so"
$ ps
PID TTY TIME CMD
2758 pts/2 00:00:00 bash
4371 pts/2 00:00:00 ps
malloc called: 184 times
total allocated memory: 302599 bytes
下面来看下PHP打桩算法在使用时出现的问题。
当构造测试用例的数据,是在函数内部被另一个外部函数所使用时,我们需要忽略外部函数所带来的影响。
需要进行“打桩”,举一个具体的例子
class DataGetter {public:
...
bool Run()
...
private:
...
Client* m_ptr_client
...
}
.....
.....
bool DataGetter::Run() {
...
std::string data
bool ret = m_ptr_client->GetData(data)
...
}
....
....
比如要对run这个函数进行单元测试,它内部调用了ptr_client->GetData(data)的方法,它是通过tcp协议从服务端取数据到data里,测试run这个函数,必然要构造data。
如果不“打桩”,要测试的话,我们就需要再从服务端去构造数据,而且还可能收到其他因素的影响。
这时候“桩”就是很好的一种技术。
那如何去构造“桩”呢。
那么如何构造呢?
原理:利用c++ virtual的特性,改变m_ptr_client指针所指向的对象,重写一个“打桩”测试类。
当然,前提是GetData的定义本身是virtual的。
假设Client的定义如下
class Client {......
public:
virtual bool GetData(std::string& data)
......
}
我们只需要重写Getdata的方法,并且当参数data被传进来时,我们可以返回特定的值。
这一套方法,google已经提供了很好的一套框架:gmock
下面介绍一下它的用法
#include "client.h" //被mock的类的头文件#include// gmock 的头文件
class MockClient : public Client {
public:
MockClient():Client() {}
MOCK_METHOD1(GetData, bool(std::string&))
}
这里使用了一个宏MOCK_METHOD1
原形是MOCK_METHOD#1(#2, #3(#4) )
#1表示被mock的函数参数个数,#2表示被mock的函数名称,#3表示被mock的函数返回值,#4表示被mock的函数参数列表
这样,一个“桩”就“打”好了。
如何正确简便地使用
首先,要先改变m_ptr_client指向的对象,对于private的变量,在前一章有描述方法,
然后测试的时候,直接将 m_ptr_client = new
MockClient()即可,不过要记得释放它之前new的资源(如果有的话),不然就内存泄露了,哈哈
使用gmock的几个宏,用一个例子简单介绍下:
EXPECT_CALL( //mock被调用时,要发生的动作*m_ptr_client, // 被mock的对象,看清楚,是对象,不是指针了
GetData(test::_) // 被mock的方法,参数为占位符
).Times(2) // 表示被调用2次
.WillOnce( 第一次调用
testing::SetArgReferee<0>(“test”), //设置第0个参数的值为“test”
testing::Return(true), //设置返回值为true
)
.WillOnce( 第二次调用
testing::SetArgReferee<0>(“test”), //设置第0个参数的值为“test”
testing::Return(false), //设置返回值为false
)
测试的原则,尽量不修改被测函数,覆盖函数的每一个分支,保证外部条件都是正确的。
你用的什么工具调试的,windows下VS系列的IDE都很方便,直接在你要调试的地方设置断点,运行的时候遇到断点就会中断,你就可以调试了,linux下用gdb一样的,使用b添加断点即可。如果这个C文件里面的代码和其它文件关联比较小,也可以直接拿出来,单独建一个工程进行调试,如果和其它文件有关联,就比较麻烦了,如果单独拿出来测试,需要构造相应的变量、条件之类的,一般我们称之为打桩测试,如果整个程序是正常的,并且有测试用例能到达你的那个C文件,那还是整体调试比较方便。
做为软件学院的同学大多数要去软件公司、游戏公司和互联网公司。我就我比较了解的互联网公司的几个跟技术有关的职位做一定的科普,希望对大家有一定的帮助,大牛请绕道。RD(Research&Development),即研发,其实就是软件工程师,或者叫程序员、码农。我们软件学院的大多数人都将从事这个职位,主要任务就是写代码,当然还有调研等工作,但都离不开编码。需要掌握的技能包编程语言、算法、脚本等。这个职位大概可以分为两个方向,一个是前端,另外一个就是后台。前端即UI,可以是网站的前端,也可以是应用程序的前端。对于网站的前端需要掌握HTML/CSS/JS、JSP/PHP/ASP.NET等东西,也可能用到JAVA等编程语言。对与应用程序的前端也分手机和桌面。手机需要了解Android呀、IPhone、Windows mobile、塞班那些个程序的开发,具体不是很了解,工资也很高。应用程序的前端的话,主要是Windows程序的开发了,那些Api什么的要比较熟,算法功底也是要有的。后台用的主要是C/C++、JAVA,算法要求更高一些,后台一般用Linux *** 作系统,对Linux要求比较了解。对于不同的系统,还有一定的业务门槛,这些只能在工作的过程中学习了。对于某些后台技术,可能还需要掌握一些数据挖掘、信息检索、自然语言处理等方面的高级知识,研究生可能要求对这些要有一定的了解,甚至是精通。QA(Quality Assurance),即测试。可能很多搞技术的都不怎么看得上测试。但我不这么认为,而且公司也都越来越重视测试了,测试拿的薪水也不比你研发的少。有的人甚至认为做测试就是简单的重复劳动,甚至可能是做点按钮的工作。但其实这都是误解,或者说前面的这些都是比较低级的测试。一般来讲,在互联网公司测试分为纯测试和开发测试两种,也可能不区分。也就是说测试并不是不要写代码,其实测试也要写代码。需要学会的技术有很多,可以说开发的那些技术你也是要懂的,还是学会使用各种测试工具,指导RD写单测,写Mock(俗称打桩),使用valgrind,搭各种测试环境,压力环境。如果高级点,还需要搞可持续化集成,要写各种各样的脚本。当然低级的反复跑程序什么的也是不可避免的。如果你懂技术,但不是那么精通的话,还是可以考虑测试职位的,尤其低于女生来说,选择测试还是比较靠谱的。说到女生,我就多插一句,女生并不是不适合做RD,RD中也有不少的MM,甚至也有很多做得非常出色的MM RD,但是你要能忍受各种各样的加班和压力。女生做QA的话,相对就要好很多,据我里了解做测试的女生还是非常多,就我所知道的百度而言,测试mm可能比测试的gg要多一些。PM(Product Manager),即产品经理。这里的经理是管理和运营的意思。产品经理也就是产品运营与管理的工作。产品经理其实是可以不懂技术的,有说PM懂技术好的,也有说PM不懂技术好的,但到底哪个好,那就不得而知了。懂技术,可能就不会提出那些无法实现的需求来,但是懂技术也可能限制和束缚你的思想。PM的很大一项工作是分析数据,并发现数据背后所隐藏的东西,所以如果你是学数学的或是数学功底好的话,会更好。其实PM对一个产品的影响要比RD大很多,现在来看,已经不是技术的时代了,很多时候都取决于产品的工作。说白了,产品是一个了解用户需求,并替用户提需求的一个工作。怎么了解呢,主要是对数据的分析和对行业的了解了。我们软件学院的同学,做产品并不是很多,其实我觉得也是一个很好选择。尤其是女生,如果你对技术不是那么感兴趣的话,而又有敏锐的洞察力的话,还是可以考虑PM这个职位的。这个职位相比RD来讲不是很累,后续的发展可能还比RD要好一些,何乐而不为呢。具体PM要了解一些什么技术,我也不甚了解,感兴趣的可以自己去网上查。OP(Operator),即运维。说表了就是管理线上机器和程序。一般成熟的互联网公司,RD是不直接管理线上服务器的。RD的程序要上线,到线上的机器上运行,首先要经过QA的测试,然后由OP *** 作上线。OP需要保证线上机器安全可靠地运行,实时监控程序的运行状态,会设置各种各样的检测脚本,报警体系。另外要实时响应各种报警,不管是半夜还是凌晨,一有问题,你就要实习响应。可能这是一个真正不适合女生做的职位。OP需要对服务非常了解,对 *** 作系统非常了解,要对Linux脚本很熟悉,有的时候也是要写程序的,比如监控程序。如果运维做的好,可能还需要写一些辅助工具,可能是网页版形式,方面运维和监控。我了解的大概就这么些东西吧,说的不对的,欢迎指正,有问题欢迎及时提出。欢迎分享,转载请注明来源:内存溢出
评论列表(0条)