惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Help Net Security
Help Net Security
G
Google Developers Blog
雷峰网
雷峰网
WordPress大学
WordPress大学
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Engineering at Meta
Engineering at Meta
Security Latest
Security Latest
T
Threat Research - Cisco Blogs
AWS News Blog
AWS News Blog
F
Full Disclosure
C
Cybersecurity and Infrastructure Security Agency CISA
T
The Exploit Database - CXSecurity.com
J
Java Code Geeks
U
Unit 42
C
Cyber Attacks, Cyber Crime and Cyber Security
V
V2EX
C
Cisco Blogs
博客园 - 司徒正美
Project Zero
Project Zero
L
LINUX DO - 热门话题
阮一峰的网络日志
阮一峰的网络日志
Blog — PlanetScale
Blog — PlanetScale
Scott Helme
Scott Helme
A
About on SuperTechFans
Hugging Face - Blog
Hugging Face - Blog
S
Securelist
小众软件
小众软件
aimingoo的专栏
aimingoo的专栏
S
Schneier on Security
G
GRAHAM CLULEY
酷 壳 – CoolShell
酷 壳 – CoolShell
Cyberwarzone
Cyberwarzone
MongoDB | Blog
MongoDB | Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 叶小钗
T
Threatpost
Recorded Future
Recorded Future
C
CXSECURITY Database RSS Feed - CXSecurity.com
宝玉的分享
宝玉的分享
N
News and Events Feed by Topic
人人都是产品经理
人人都是产品经理
The Register - Security
The Register - Security
S
Security Archives - TechRepublic
博客园 - Franky
N
News | PayPal Newsroom
Simon Willison's Weblog
Simon Willison's Weblog
S
SegmentFault 最新的问题
W
WeLiveSecurity
A
Arctic Wolf
B
Blog

博客园 - AaronChen

程序员导师制(师傅带徒弟)指导意见 C++程序员进阶书籍推荐 单元测试 2009年研发经理工作总结 人为什么活着读后感 高效研发团队管理的秘诀 memset、memcpy使用陷阱 用Visual C++设计屏幕抓图程序 C++总结 友元类和友元函数(转) 今天,让我们一起努力 C++测试全攻略(转) CppUnit单元测试 电信级系统性能分析 不许移动鼠标到照片上 仿银行密码输入保护器(软键盘) 如何有效地编写软件 史上最伟大的十大程序员 教你怎样快速DIY自己的博客园SKIN petshop4.0 详解之八(PetShop表示层设计)
测试全攻略
AaronChen · 2011-08-27 · via 博客园 - AaronChen
 

在c++的世界里,程序设计的优雅让位于程序的稳定性、健壮性。“好程序是测出来的”这句话在C++领域里得到了充分体现。下面是我在开发中使用的测试方法,抛砖引玉,和大家交流下。
测试期间,关闭对core文件的限制,使用命令:ulimit -c unlimited
(1)开发阶段,使用cppunit维护测试用例。我一般是用于测试解析类、算法类。
http://sourceforge.net/projects/cppunit/下载最新版本,解压,看安装文档,一般是./configure & make & make install。
下面举例说明我使用cppunit的方法。假设自己的源码位于src目录下,里面有class1.h/class1.cpp/class2.h/class2.cpp。相对src建立平级目录test存放测试工程,为class1/class2分别建立测试类文件testClass1.h/testClass2.h,建立main函数所在文件test.cpp、makefile。
testClass1.h代码如下,testClass2.h类似。

#include "class1.h"
#include <iostream>
#include "cppunit/TestRunner.h"
#include "cppunit/TestResult.h"
#include "cppunit/TestResultCollector.h"
#include "cppunit/extensions/HelperMacros.h"
#include "cppunit/BriefTestProgressListener.h"
#include "cppunit/extensions/TestFactoryRegistry.h"
#include "cppunit/TextOutputter.h"
#include "cppunit/CompilerOutputter.h"
#include "cppunit/TestCaller.h"
class testClass1:public CPPUNIT_NS::TestFixture
{
   CPPUNIT_TEST_SUITE(testClass1);
   CPPUNIT_TEST(testCase1);
   CPPUNIT_TEST(testCase2);
   CPPUNIT_TEST_SUITE_END();
    public:
        virtual void setUp(){}
        virtual void tearDown(){}
        void testCase1()
    {
            testClass1 a;
            a.oper..;
            CPPUNIT_ASSERT_EQAL(a.get..,);
        }
        void testCase2()
    {
            CPPUNIT_ASSERT(==);
        }
};

test.cpp代码如下:

#include "testClass1.h"
#include "testClass2.h"
#include <iostream>
#include "cppunit/TestRunner.h"
#include "cppunit/TestResult.h"
#include "cppunit/TestResultCollector.h"
#include "cppunit/extensions/HelperMacros.h"
#include "cppunit/BriefTestProgressListener.h"
#include "cppunit/extensions/TestFactoryRegistry.h"
#include "cppunit/TextOutputter.h"
#include "cppunit/CompilerOutputter.h"
#include "cppunit/TestCaller.h"
 CPPUNIT_TEST_SUITE_REGISTRATION(testClass1);
 CPPUNIT_TEST_SUITE_REGISTRATION(testClass1);
int main()
  {
    CPPUNIT_NS::TestResult controller;
    CPPUNIT_NS::TestResultCollector result;
    controller.addListener( &result );       
    CPPUNIT_NS::TestRunner runner;
    runner.addTest( CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest() );
    runner.run( controller );
    CPPUNIT_NS::CompilerOutputter out( &result, std::cout );
    out.write();
    return 0;
}

makefile文件如下:

EXE=test
SRC=test.cpp
INC_PATH=-I ../src -I (cppunit头文件的目录) -I(依赖的其他头文件路径)
LIB_PATH=-L (cppunit动态库所在的目录) -L (依赖的其他库所在目录)
    LIB=-lcppunit -ldl
all:
    g++ $(SRC) $(LIB_PATH) $(LIB)  $(INC_PATH) -o $(EXE)
再有新的需要测试类,增加相应的测试类,稍微修改下test.cpp即可(增加一句#include,一句CPPUNIT_TEST_SUITE_REGISTRATION)。
保证开发结束后,解析类、算法类等不会有错误。
(2)白盒测试阶段。
这个基本是功能逻辑性测试,检测所有数据结构按要求变化以及保证各线程之间变化的一致性。这是最基本也是最全面的一次测试,保证测试的功能覆盖率100%。白盒测试期间可以在代码里加一些宏编译选项或者增加程序交互功能用于观察所有数据结构的变化。
保证测试完毕没有功能性、逻辑性的错误。
(3)内存测试阶段。使用valgrind检测显式内存泄漏、内存读写错误。
http://www.valgrind.org/下载最新版本,解压,看安装文档,一般是./configure & make & make install。
检测内存一般使用命令valgrind --tool=memcheck -v --leak-check=full ./待测程序错误的地方会用==×××==(×××表示数字)标出。
使用一路模拟客户端做陪测。
保证测试完毕,单路客户端陪测的情况下没有任何的显式内存泄漏,没有任何的内存读写错误。
(4)写批量客户端模拟程序。建议熟悉一门方便socket编程的脚本语言,推荐perl。脚本语言简单,实现快速,特适合做陪测。
首先写一个能读取配置文件信息,按配置文件的要求向相应的server,按配置文件的流程发送信令的perl程序。
下面是我rtsp相关的一个server陪测的配置文件:


ip=127.0.0.1
port=9115
url=rtsp://172.24.202.190:554/asset/service?USERID=320101312345670001&ChanelNo-PUID=0-320101000200000001&PlayMethod=0
<s,2>
<p,2>
<u,2>
<p,2>
<t,2>


其中ip是server IP,port是rtsp端口,url是发送信令带的url。<>表示按顺序发送的信令,这个配置文件表示先发送一个setup,然后sleep 2秒,再发送一个play,然后sleep 2秒,继续......这个程序可作为(3)中的陪测程序

在上面程序的基础上修改,读取配置文件后,死循环按顺序发送信令,假设该程序称做B。
写一个新的perl文件,完成如下功能,起几十路使用某配置文件的B程序,sleep几秒后,再起几十路使用其它配置文件的B程序.....,或者一起起也可以,自行设计,最后killall所有,从头循环运行。
总之尽可能的模拟客户端的所有行为,包括突然断联等,并且保证一定的压力。
(5)压力下测试内存。继续在valgrind下测试,使用(4)中的测试脚本做配测。
保证压力下无异常状态、无数据不一致状态、无显式内存泄漏、无内存读写异常
(6)稳定性以及内存泄漏测试。
陪测脚本起几百路客户端,保证主程序的cpu占用率在70%以上,持续运行20多小时。
测试期间,关注进程对内存的占用率,是保持在恒定水平还是随运行时间的增长而增长。
测试完毕,保证主程序负荷运行长时间而不宕机、没有内存泄漏发生。
(7)代码覆盖率测试。gcov
gcov是随gcc安装的,可以检查陪测程序对目标程序的代码覆盖情况。
不断修改测试脚本,保证测试尽量全面。代码被执行的次数也可以做为以后性能测试的一个参考。
(8)性能测试。gprof
同gcov一样,gprof也是随gcc安装的,它可以检测目标程序中所有函数的调用时间,并根据消耗时间排序,方便找出性能瓶颈。
找出系统的主要性能瓶颈,经过性能测试后,一般会发现影响系统的主要因素还是数据结构和算法。

测试期间,任何的coredump/任何的内存读写异常,务必处理掉。墨菲法则说,一个事情如果有可能变糟,事实则是会变的更糟。任何一个微小的、出现几率极小的bug,如果不在研发测试阶段解决,都可能造成以后更大代价的返工,甚至给客户的运营带来灾难。希望在每个人身上生效的都是马太效应,而不是墨菲法则。