51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 5437|回复: 1
打印 上一主题 下一主题

讨论_求助_如何用CppUnit测试界面类/无返回值函数_VC

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2006-11-15 11:58:11 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我有一个继承自mfcCButton 的类CXButton
class CXButton: public CButton
{
public:
        //##ModelId=4558394500CD
        CXButton();
public:
        int m_iSpeed;
        void SetSpeed(int nSpeed) { m_iSpeed = nSpeed; }
        int GetSpeed() { return m_iSpeed; }
public:

// Overrides
        // ClassWizard generated virtual function overrides
        //{{AFX_VIRTUAL(CButtonEx)
        //}}AFX_VIRTUAL

// Implementation
public:
        virtual ~CXButton();
        // Generated message map functions
protected:
        //{{AFX_MSG(CButtonEx)
        afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
        afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
        afx_msg void OnMouseMove(UINT nFlags, CPoint point);
        //}}AFX_MSG
        DECLARE_MESSAGE_MAP()
};
问题,我如何用CppUnit来测试这个类的如下三个成员函数呢:
        afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
        afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
        afx_msg void OnMouseMove(UINT nFlags, CPoint point);
因为这三个成员函数都没有返回值,而CppUnit的Asset都是根据返回值了做判断的。。
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏
回复

使用道具 举报

该用户从未签到

2#
发表于 2006-11-15 12:14:43 | 只看该作者
关于界面类的测试:
界面类的测试通常是很麻烦的,不要把业务代码写在界面类中,而是写到相应的业务类中,消息处理函数调用业务代码执行需要的操作,单元测试时只测试业务类。
你这个类可能不涉及资源,这样的话可以加到测试工程中进行测试,如果涉及到资源,加入到测试工程是很难通过编译的。不把业务代码独立出来,不但造成单元测试很麻烦,而且也不利于以后的升级维护,属于很糟糕的设计。

关于预期输出判断:
我已经很久没用过CPPUNIT了,不太记得,不过我相信预期输出不会仅限于返回值,否则是无法应用的。一个函数,它可能使用了输出参数,修改了成员变量或全局变量,这些都是要判断的,不限于返回值。输入数据也是要考虑这些的,要不然,在实际工作中是做不了单元测试的。我把Visual Unit帮助中关于输入和输出的说明贴出来,可能有一定参考价值(Visual Unit有免费版本):

输入数据
自动为参数生成输入数据,其中,“ParamName = ”中的“=”仅表示这个对象可能需要赋值,要根据实际情况灵活处理,请参考下面的示例(黑色部分是由VU生成的,红色部分是由用户填写的。行末不要加分号,VU会自动删除“=”):

//对于基本数据类型或定义了=操作符的类型,直接将数值填在“=”后面
int i = 0
CString name = "Smith"

//未定义=操作符的结构,用.操作符给各个域赋值,VU会自动删除“=”
PERSON person =
person.name = "Smith"
person.age = 20


//可以调用对象的构造函数,VU会自动删除“=”
CMyClass obj("name", 20) =

//可以调用对象的初始化函数
CMyClass obj =
obj.Init()

//仅用于输出的参数可以不作任何处理
CString name =

为了简化问题,如果参数是指针,指针的指针,或是引用,也直接生成对象,用户只需为对象设定初始值,VU会自动做适当处理,参考测试用例代码解析。如果要给指针赋空值,则要切换到代码模式,直接修改代码。

对于定义了=操作符的被测试对象,可以直接赋值。无论类型是什么,VU都用pObj表示被测试代码的指针:
//类似于CString的类
*pObj = "abcde"
//用另一个对象赋值
*pObj = CRect(0, 0, 0, 0)

可以视需要访问成员变量、全局变量,调用其他成员函数,语法如下:

//可以用.操作符直接访问成员变量
.mName = "王老五"
.mAge  = 100
.mName.Empty()
.mObj.Init()


//可以用.操作符调用其他成员函数
.PreCondition()

//其他地方定义的全局变量,如果是可见的,则可以直接访问
gVar = 0

只要被测试的类中定义了UNIT_TEST宏,就可以直接访问私有或保护的成员变量,参见添加测试支持代码。

可以选择输入数据的类别,一般来说,输入数据分为:正常输入、边界输入、非法输入,参见测试用例概述。可以用上下箭头改变用例的排列顺序。
可以添加简单注释:
针对整个测试用例的注释在代码模式下编辑,但输入数据中也可以添加简单的注释。如果要在一行代码后添加注释,则代码后的分号不能省略,否则会产生编译错误。下面是从实际项目中拷贝的一个测试用例的输入数据:
CTokenList ioList
//调用成员函数ReadTokenList生成输入数据
.ReadTokenList(ioList, "int i=0;"); //更多的用例只要修改第二个参数就行了
POSITION ioPos = ioList.GetHeadPosition(); //指向第一项

预期输出
预期输出与输入数据的语法是一样的。如果被测试函数有返回值,会保存在名为ret的变量里,并在预期输出的框中生成"ret == ",也可以添加其他的预期输出,例如成员变量或全局变量,与输入数据一样,可以用.操作符直接访问成员变量。每行填写一项预期输出,运算结果为布尔值的表达式都是合法的预期输出,不一定是等式,如下面的预期输出都是可行的:
ret == 3125
.mAge > 20
ret != 0
i<0 || ret>=j
str.IsEmpty()
.mRect.leftTop.x == 100


对于定义了==操作符的被测试对象,可以直接用==操作符判断预期输出,记住:pObj就是被测试对象的指针:
*pObj == "abcd"

与输入数据类似,“ret ==” 的“==”仅表示这里可以进行逻辑比较,如果返回值是基本数据类型或定义了==操作符的其他数据类型,可以将预期的输出结果直接填在“==”后,否则可以调用它的数据接口判断输出是否符合预期,如:
ret.GetName() == "MyName"
ret->IsEmpty()
注意:无论返回值是什么类型,都用ret表示。

VU会把第一个点操作符替换为"pObj->",如".mAge=0",生成对应的测试代码"pObj->mAge=0;",因此,表示成员变量的点操作符只能作为第一个字符。例如:.mPhase.IsEmpty()是可以的,但!.mPhase.IsEmpty()则是不合法的,会产生编译错误,这种情况可以直接写:!pObj->mPhase.IsEmpty()。

由上述可以看出,输入数据和预期输出是非常灵活的,具有很好的适应能力,即使是复杂的输入输出,也能处理。用户只需要填写第一个测试用例,其他的测试用例通过拷贝现有测试用例并修改的办法建立。在特殊情况下,可以切换到代码模式下直接编辑代码。

可以在预期输出中添加注释,但单独一行的注释只能使用//...,而与一项预期输出同一行的注释只能使用/*...*/,如
//在预期输出中,单独一行的注释只能使用//...,不能使用/*...*/
ret == 0 /*这里不能使用//...,因为预期输出会被TEST_ASSERT()宏包装*/

后置操作
有时可能需要在运行测试后执行一些操作,例如删除对象指针。后置操作也在预期输出部分填写,但VU会把预期输出用TEST_ASSERT()宏包装,因此要使用特别标记使VU能识别后置操作:在后置操作后添加://!。//!后可以添加其他注释。

例如,在预期输出中填写:
.mName.Empty(); //! 这个是一般代码,不是预期输出
.mName.IsEmpty()
生成对应代码如下:
pObj->mName.Empty(); //! 这个是一般代码,不是预期输出
TEST_ASSERT( pObj->mName.IsEmpty() );

注意,后置操作不能省略语句后的分号,否则会产生编译错误。

[ 本帖最后由 VisualUnit 于 2006-11-15 12:24 编辑 ]
回复 支持 反对

使用道具 举报

本版积分规则

关闭

站长推荐上一条 /1 下一条

小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

GMT+8, 2024-11-24 02:19 , Processed in 0.071379 second(s), 27 queries .

Powered by Discuz! X3.2

© 2001-2024 Comsenz Inc.

快速回复 返回顶部 返回列表