【第三周】【】cppunit!
coding.net地址:https://coding.net/u/Boxer_
ssh:git@git.coding.net:Boxer_/homework.git
https://coding.net/user
本次作业过程还是比较坎坷的,主要是前期准备工作比较复杂,这次工作是了解,熟悉并能使用单元测试框架,主要包括junit,cppunit,cunit。这是上次上课老师留下来的,在课堂上老师介绍了一些这些东西,我努力认真听了一下,然后只记下了名字。由于是用的c++和c编写的代码,我理所应当选用cppunit。
一,cppunit的了解:
当着手这个任务开始,已经是周一下午了,算起来距离deadline已经不远了,倒不是我懒也不是拖延(至少不是主要原因),而是由于其他不可抗事务。一般有这样的规律:距离deadline越近,效率越高。所以从这种意义上来讲,我也是因祸得福,节约了不必要的时间的浪费,毕竟考试前一晚上的复习效率是最高的嘛,而我居然拿出了比一学期考试复习还认真的态度应对一周普通软件工程的作业。还有关于拖延的相关信息大家可以看一下这个视频http://open.163.com/movie/2016/3/Q/E/MBHQSM52F_MBI15O7QE.html
关于cppunit单元测试,我之前不怎么了解 ,选择了百度一下,而结果让我感到不舒服,因为教程基本都是十年前的,推荐的ide还是vc++6.0。这导致了我走了很多弯路,虽然教程是很早之前的,而教程里留下的sourceforge代码托管网站的地址居然隔了十几年还能用,非常靠谱,反观百度云分享链接几个月就应该损失殆尽了。在SourceForge上cppunit的代码一直在不断更新,这让我通过教程给的十年前的地址下载下来了最新的官方项目。但很遗憾的是,无法使用。
可以看到这里面所有的扩展名后面又增加了,v的后缀,不知道什么原因,可能这是服务器版本。导致所有文件无法正常执行了,因为被改了后缀的子文件已经忘记了自己的打开方式,就犹如一个个孤岛,孤立无援。所以这是一个大坑,不知情况者要在这里浪费不少时间。
之后我就一直在网上寻找教程,但是符合自己口味的教程实在太少,前几页的结果也看了很多了,都是零几年写的了,很难理解。就算才开始能跟上作者的步骤,但是作者可能下一步就很跨越,再也理解不能。我厌烦了,我就问老师,老师老师这cppunit是不是已
经淘汰不用了,能不能写个教程。
(部分聊天记录)
之后我明白了,我不会,找不到一定是我还不够努力。既然这是个成熟的软件或者是框架,就一定能用并且也有人用过。然后我想距离现在越短的教程大概越靠谱,百度应该能添加搜所条件。我找了一下果然可以搜最近时间的结果。
我看了下最近一年的文章,搜到了其他人在博客园的教程,比之前我找的教程靠谱233倍。
虽然事后我感觉也是个坑,因为我找他的步骤详细做了,最后几步过不了他提供的github上提供的代码。我看到了他的编译文件,少了几个文件,相当于少了很多类。而我程序报错的代码恰好是因为几个类的定义找不到,当然这是后面才知道的了。然而虽然没按照作者所说的路线走下去,在按照作者步骤做的过程中,我成功的编译了部分文件,得到了部分结果,了解了这个框架的部分构成,更重要的是得到了继续寻找的勇气。
所以个人的经历不是简单的用值不值,简单的得失来衡量的。急于到达目的地,不光跑错了方向,并且也失去了一路的风景。后来我刻意找了一下老版本的cppunit,发现是正常的,之后我用之前教程里得到的经验编译了一下。看了下示例项目,初步了解了下该框架。
鉴于本人学习该框架的痛苦经历,加上有些同学向我对该问题进行交流。我决定说一下流程。算是个简单的教程。
1,你要确保自己有个c++编译器,最好是ide,这里推荐下vs2008。 vs2013或者更高编译出来的东西有问题,我的win10+vs2013环境编译出来的东西无法运行,而实验室的win7+vs2008可以。
2,在http://downloads.sourceforge.net/cppunit/cppunit-1.12.1.tar.gz下载软件,
cppunit版本是cppunit-1.12.1。这个网址打开后过一会会自动下载。
3,解压后是这样的。
4,进入cppunit目录下src文件夹,用VS打开CppUnitLibraries文件,提示需要转换,选择确定。
5,之后迁移项目要花点时间,然后点击生成-批生成-全部生成。之后编译过程比较长,弹出对话框点确定就行了。
6,编译完之后,我们就得到了以下文件,打开testpluginrunner还有图形界面。
7,我们不使用图形界面,退回到一级目录,然后打开example,点击examples.dsw,看到有几个项目。左边的是加载到vs里面的,右边的是文件里的。对比我们可以发现,右边文件夹名字在左边出现的,应该是示例项目。
8,有个项目名字为simple,应该是简单的示例代码,我们点开simple。simple有四个文件,除了我们熟悉的.cpp,.h外还有没见过的makefile文件。
在mian函数的return前面添加system("pause");然后右键项目,生成,然后我们找example/simple/debug下面的simple.exe,看到以下结果。
二,cppunit的进一步了解
再让我们看一下代码
main文件代码
#include <cppunit/BriefTestProgressListener.h>
#include <cppunit/CompilerOutputter.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/TestResult.h>
#include <cppunit/TestResultCollector.h>
#include <cppunit/TestRunner.h> int main( int argc, char* argv[] )
{
// Create the event manager and test controller
CPPUNIT_NS::TestResult controller; // Add a listener that colllects test result
CPPUNIT_NS::TestResultCollector result;
controller.addListener( &result ); // Add a listener that print dots as test run.
CPPUNIT_NS::BriefTestProgressListener progress;
controller.addListener( &progress ); // Add the top suite to the test runner
CPPUNIT_NS::TestRunner runner;
runner.addTest( CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest() );
runner.run( controller ); // Print test in a compiler compatible format.
CPPUNIT_NS::CompilerOutputter outputter( &result, CPPUNIT_NS::stdCOut() );
outputter.write();
system("pause");
return result.wasSuccessful() ? : ;
}
ExampleTestCase.h文件代码
#ifndef CPP_UNIT_EXAMPLETESTCASE_H
#define CPP_UNIT_EXAMPLETESTCASE_H #include <cppunit/extensions/HelperMacros.h> /*
* A test case that is designed to produce
* example errors and failures
*
*/ class ExampleTestCase : public CPPUNIT_NS::TestFixture
{
CPPUNIT_TEST_SUITE( ExampleTestCase );
CPPUNIT_TEST( example );
CPPUNIT_TEST( anotherExample );
CPPUNIT_TEST( testAdd );
CPPUNIT_TEST( testEquals );
CPPUNIT_TEST_SUITE_END(); protected:
double m_value1;
double m_value2; public:
void setUp(); protected:
void example();
void anotherExample();
void testAdd();
void testEquals();
}; #endif
ExampleTestCase.cpp文件代码
#include <cppunit/config/SourcePrefix.h>
#include "ExampleTestCase.h" CPPUNIT_TEST_SUITE_REGISTRATION( ExampleTestCase ); void ExampleTestCase::example()
{
CPPUNIT_ASSERT_DOUBLES_EQUAL( 1.0, 1.1, 0.05 );
CPPUNIT_ASSERT( == );
CPPUNIT_ASSERT( == );
} void ExampleTestCase::anotherExample()
{
CPPUNIT_ASSERT ( == );
} void ExampleTestCase::setUp()
{
m_value1 = 2.0;
m_value2 = 3.0;
} void ExampleTestCase::testAdd()
{
double result = m_value1 + m_value2;
CPPUNIT_ASSERT( result == 6.0 );
} void ExampleTestCase::testEquals()
{
long* l1 = new long();
long* l2 = new long(); CPPUNIT_ASSERT_EQUAL( , );
CPPUNIT_ASSERT_EQUAL( 12L, 12L );
CPPUNIT_ASSERT_EQUAL( *l1, *l2 ); delete l1;
delete l2; CPPUNIT_ASSERT( 12L == 12L );
CPPUNIT_ASSERT_EQUAL( , );
CPPUNIT_ASSERT_DOUBLES_EQUAL( 12.0, 11.99, 0.5 );
}
虽然我对该框架一点不熟悉我们发现了以下代码
CPPUNIT_ASSERT( 12L == 12L );//两个长整形12的大小,为真 CPPUNIT_ASSERT_EQUAL( , );//比较12和13是否相等,不相等不通过测试 CPPUNIT_ASSERT_DOUBLES_EQUAL( 12.0, 11.99, 0.5 )//比较两个double的值是否相差大于0.5.
ExampleTestCase.h文件代码写的是各测试函数的声明。
main函数写的是测试相关代码,发现跟ExampleTestCase中的各函数一点关系都没有,可以安心通过更改部分代码来实现想要进行的但与测试。
三,cppunit的简单实践
本次测试是要测试四则运算程序中关于具体实现运算的两个函数,分别是convert2RPN()和calculateRPN(),二者功能是把算式转化为后缀表达式,并且计算。
以下为测试用例。
test1:+ test2:- test3:* test4:/ test5:/ test6:+*- test7:+*(-) test8:÷((+)÷) test9:(/++) 40.1756
以下为测试代码
ExampleTestCase.h
#ifndef CPP_UNIT_EXAMPLETESTCASE_H
#define CPP_UNIT_EXAMPLETESTCASE_H
#include<string>
#include<iostream>
#include <cppunit/extensions/HelperMacros.h>
using namespace std;
class ExampleTestCase : public CPPUNIT_NS::TestFixture
{
CPPUNIT_TEST_SUITE( ExampleTestCase );
CPPUNIT_TEST( test1 );
CPPUNIT_TEST( test2 );
CPPUNIT_TEST( test3 );
CPPUNIT_TEST( test4 );
CPPUNIT_TEST( test5 );
CPPUNIT_TEST( test6 );
CPPUNIT_TEST( test7 );
CPPUNIT_TEST( test8 );
CPPUNIT_TEST( test9 );
CPPUNIT_TEST_SUITE_END();
public:
double res;
string s;
void test1();
void test2();
void test3();
void test4();
void test5();
void test6();
void test7();
void test8();
void test9(); }; #endif
ExampleTestCase.cpp
之前的代码就不占篇幅了,折叠了先。
void convert2RPN(string &s) {
stringstream ss;
stack<char> stk;
for (size_t i = ; i < s.length(); i++) {
if (isdigit(s.at(i))) {
ss << s.at(i);
if ((i < s.length() - && !isdigit(s.at(i + )))
|| i == s.length() - ) {
ss << ' ';
}
}
else {
if (stk.empty()) {
stk.push(s.at(i));
}
else {
switch (s.at(i)) {
case '(':
stk.push(s.at(i));
break;
case ')':
while (stk.top() != '(') {
ss << stk.top();
stk.pop();
}
stk.pop();
break;
case '+':
case '-': while (!stk.empty() && stk.top() != '(') {
ss << stk.top();
stk.pop();
}
stk.push(s.at(i));
break;
case '*':
case '/':
while (!stk.empty() && (stk.top() == '*' || stk.top() == '/')) {
ss << stk.top();
stk.pop();
}
stk.push(s.at(i));
break;
}
}
}
}
while (!stk.empty()) {
ss << stk.top();
stk.pop();
}
s = ss.str();
}
convert2RPN
double calculateRPN(const string &s) {
stack<float> stk;
for (size_t i = ; i < s.length(); i++) {
if (isdigit(s.at(i))) {
int e = atoi(&s.at(i));
int t = e / ;
while (t > ) {
i++;
t /= ;
}
i++;
stk.push(e);
}
else {
float r = stk.top();
stk.pop();
float l = stk.top();
stk.pop();
float result;
switch (s.at(i)) {
case '+':
result = l + r;
break;
case '-':
result = l - r;
break;
case '*':
result = l * r;
break;
case '/': result = l / r;
break;
}
stk.push(result);
}
} return stk.top();
}
calculateRPN
void ExampleTestCase::test1()
{
string s ="1+1";
convert2RPN(s);
double res1 = calculateRPN(s);
double res2 = ;
CPPUNIT_ASSERT_DOUBLES_EQUAL( res1, res2, 0.05 );
} void ExampleTestCase::test2()
{
string s= "55-5";
double res2 = ;
convert2RPN(s);
double res1 = calculateRPN(s);
CPPUNIT_ASSERT_DOUBLES_EQUAL( res1, res2, 0.05 );
}
void ExampleTestCase::test3()
{
string s= "33*3";
double res2 = ;
convert2RPN(s);
double res1 = calculateRPN(s);
CPPUNIT_ASSERT_DOUBLES_EQUAL( res1, res2, 0.05 );
}
void ExampleTestCase::test4()
{
string s= "50/5";
double res2 = ;
convert2RPN(s);
double res1 = calculateRPN(s);
CPPUNIT_ASSERT_DOUBLES_EQUAL( res1, res2, 0.05 );
}
void ExampleTestCase::test5()
{
string s= "1/1";
double res2 = ;
convert2RPN(s);
double res1 = calculateRPN(s);
CPPUNIT_ASSERT_DOUBLES_EQUAL( res1, res2, 0.05 );
} void ExampleTestCase::test6()
{
string s= "21+23*12-6";
double res2 = ;
convert2RPN(s);
double res1 = calculateRPN(s);
CPPUNIT_ASSERT_DOUBLES_EQUAL( res1, res2, 0.05 );
} void ExampleTestCase::test7()
{
string s= "21+23*(12-6)";
double res2 = ;
convert2RPN(s);
double res1 = calculateRPN(s);
CPPUNIT_ASSERT_DOUBLES_EQUAL( res1, res2, 0.05 );
}
void ExampleTestCase::test8()
{
string s= "8/((49+5)/27)";
double res2 = ;
convert2RPN(s);
double res1 = calculateRPN(s);
CPPUNIT_ASSERT_DOUBLES_EQUAL( res1, res2, 0.05 );
} void ExampleTestCase::test9()
{ string s= "(88/17+31+4)";
double res2 = 40.1756;
convert2RPN(s);
double res1 = calculateRPN(s);
CPPUNIT_ASSERT_DOUBLES_EQUAL( res1, res2, 0.05 );
}
考虑到比较的结果是浮点数所以用了 CPPUNIT_ASSERT_DOUBLES_EQUAL,一二参数是要对比大小的参数,第三个参数是前二者的相差的阀值,一二参数若大于这个阀值,测试样例便不能通过。
main函数未做更改。
调试过程中出现过几次错误(其余n多艰难调试过程省略,)。
主要是因为再输入测试用例的过程中夹杂了汉语的括号,导致程序崩溃,虽然可以过编译,但无法正常执行。
最后改正了测试用例后的结果:
测试点 4和5 没用通过,我们再回顾一下测试用例。
test1:+ test2:- test3:* test4:/ test5:/ test6:+*- test7:+*(- test8:÷((+)÷) test9:(/++) 40.1756
可以看到第四个测试用例答案是错的,第五个出现了除零错误,结果是无限大的数。
可以看这两个函数还是比较健壮的。除零错误在代码中可以过滤掉,不进入计算。
修改了测试用例的答案后(一般不是修改程序吗?),程序顺利的通过了测试点。
没有错误的测试界面是简洁很多的。
类别 |
内容 |
开始时间 |
结束时间 |
间断时间 |
净时间 |
搜集情报 |
对有关c++单元测试的情报进行搜集 |
周一 12:29 周二 10:31 |
周一 24:00 周二 22:00 |
255min 200min |
406min 489min |
研究熟悉框架 |
主要是看example研究代码 |
周二 22:00 周三 11:55 周三 15:05 |
周三00:40 周三 13:20 周三 18:00 |
5min 20min 30min |
155min 85min 145min |
写博客 |
其实与前面穿插进行,做一部分写一部分。 |
周三 20:50 |
周三23:30 |
20min |
140min |
体会:
本次作业完成感觉是最累的一次,特别是找相关资料的时候,那种花费了大量时间一次又一次一无所获的感觉,那种面对多年前文献的无力感,因为看不懂,他所说的东西已经不好下载了。现在的环境都是win7和win10跟以前也大有不同了。但好在最后有一些小小的收获。刚开始可以编译运行示例代码的,心情是开心的,但是那些示例工程的代码由于是自己的框架,相关函数和类很难看懂,我那一瞬间感觉自己已经感觉不会编程了,后来慢慢地尝试去看,发现其实并不难,或者自己找到了可以自己提升的途径。还是比较简单的方法,既然原示例工程可以运行,那么我就可以每一次做一点修改,不断观察编译以及运行结果,靠几个简单的函数让我的代码做一下简单的测试。由于时间有限,我打算看后面较复杂工程的代码还没看,我觉得通过这个方法,我可以逐渐更熟悉这个框架,并且提高自己的工程能力,这次这个经历锻炼了我面对工程的综合解决路线。代码不是工程的全部,想要做好一个东西包括收集资料,下载软件代码,不断自己尝试,包括后面的单元测试,真正算是一项工程,包括了很多方面。总之,通过本次作业,我体验到了以前没有过的经历,感觉自己的能力更加全面了。
【第三周】【】cppunit!的更多相关文章
- 三周,用长轮询实现Chat并迁移到Azure测试
公司的OA从零开始进行开发,继简单的单点登陆.角色与权限.消息中间件之后,轮到在线即时通信的模块需要我独立去完成.这三周除了逛网店见爱*看动漫接兼职,基本上都花在这上面了.简单地说就是用MVC4基于长 ...
- Coursera系列-R Programming第三周-词法作用域
完成R Programming第三周 这周作业有点绕,更多地是通过一个缓存逆矩阵的案例,向我们示范[词法作用域 Lexical Scopping]的功效.但是作业里给出的函数有点绕口,花费了我们蛮多心 ...
- JAVA第三周作业(从键盘输入若干数求和)
JAVA第三周作业(从键盘输入若干数求和) 在新的一周,我学习了JAVA的IO编程.下面的代码实现了从键盘输入若干数求和的目标.import java.util.Scanner; public cla ...
- 20145213《Java程序设计》第三周学习总结
20145213<Java程序设计>第三周学习总结 教材学习内容总结 正所谓距离产生美,上周我还倾心于Java表面的基础语法.其简单的流程结构,屈指可数的基本类型分类,早已烂熟于心的运算符 ...
- 20145304 Java第三周学习报告
20145304 <Java程序设计>第三周学习总结 教材学习内容总结 1.定义类: 类定义时使用class关键词,建立实例要使用new关键词. 代码如下: /*定义类 书上例子 衣服的型 ...
- 20145330《Java程序设计》第三周学习总结
20145330 <Java程序设计>第三周学习总结 第三周知识的难度已经逐步上升,并且一周学习两章学习压力也逐渐加大,需要更高效率的来完成学习内容,合理安排时间. 类与对象 对象(Obj ...
- 20145337《Java程序设计》第三周学习总结
20145337 <Java程序设计>第三周学习总结 教材学习内容总结 类与对象 类与对象的关系:要产生对象必须先定义类,类是对象的设计图,对象是类的实例.我觉得在视频中对类与对象关系的描 ...
- Linux内核设计第三周——构造一个简单的Linux系统
Linux内核设计第三周 ——构造一个简单的Linux系统 一.知识点总结 计算机三个法宝: 存储程序计算机 函数调用堆栈 中断 操作系统两把宝剑: 中断上下文的切换 进程上下文的切换 linux内核 ...
- 20145218 《Java程序设计》第三周学习总结
20145218 <Java程序设计>第三周学习总结 教材学习内容总结 定义类 编写程序要产生对象就要先定义类.类是对象的设计图,对象是类的实例.类定义时使用class关键词,建立实例时, ...
随机推荐
- WPF样式、模板、装饰器学习
[代码]
- Oracle入门第一天(上)——简介与安装
一.Oracle介绍 Oracle 公司是全球最大的信息管理软件及服务供应商,成立于1977年 Oracle 公司因其复杂的关系数据库产品而闻名.Oracle的关系数据库是世界第一个支持SQL语言的 ...
- 20155315庄艺霖第三次作业之Linux初体验
Linux初体验 安装Linux三两事 老师的作业要求基于VirtualBox安装Linux系统,我一开始下载了VB但是电脑运行不了,后来看网上的教程下载了VMware,才算开始了我的Linux之旅. ...
- 20155317 2016-2017-2 《Java程序设计》实验一 Java开发环境的熟悉
20155317 2016-2017-2 <Java程序设计>实验一 Java开发环境的熟悉 实验内容 使用JDK编译.运行简单的Java程序: 使用IDEA 编辑.编译.运行.调试Jav ...
- 实现Django ORM admin view中model字段choices取值自动更新的一种方法
有两个表,一个是记录网站信息的site表,结构如下: CREATE TABLE `site` ( `id` ) unsigned NOT NULL AUTO_INCREMENT, `name` ) N ...
- 【MongoDB】NoSQL Manager for MongoDB 教程(进阶篇)
项目做完,有点时间,接着写下第二篇吧.回顾戳这里 基础篇:安装.连接mongodb.使用shell.增删改查.表复制 本文属于进阶篇,为什么叫进阶篇,仅仅是因为这些功能属于DB范畴,一般使用的不多, ...
- 【LG3234】[HNOI2014]抄卡组
题面 题解 分三种情况: 若所有串都没有通配符,直接哈希比较即可. 若所有串都有通配符, 把无通配符的前缀 和 无通配符的后缀哈希后比较即可. 中间部分由于通配符的存在,一定可以使所有串匹配. 若部分 ...
- Retinex图像增强和暗通道去雾的关系及其在hdr色调恢复上的应用
很多人都认为retinex和暗通道去雾是八杆子都打不着的增强算法.的确,二者的理论.计算方法都完全迥异,本人直接从二者的公式入手来简单说明一下,有些部分全凭臆想,不对之处大家一起讨论. 首先,为描述方 ...
- cogs696 longest prefix
cogs696 longest prefix 原题链接 IOI1996原题? 其实这题我不会. map+string+手动氧气大法好 //就是这么皮(滑稽 Code // It is made by ...
- jsp命名规则
jsp也用驼峰规则命名即可,不要使用下划线,否则在tomcat中容易出现解析错误