本学习指南介绍了如何使用QTestLib框架的一些特性,分为4章:

  1. 编写一个单元测试程序

  2. 数据驱动测试

  3. 模拟GUI事件

  4. 重复GUI事件

第一章 编写一个单元测试程序

文件列表:

在第一章我们将会学习怎样为一个类编写并执行一个简单的单元测试程序。

编写测试程序

假设你要测试QString类的行为。首先,你需要一个用于包含测试函数的类。这个类必须从QObject继承:

#include <QtTest/QtTest>

class TestQString: public QObject

{

    Q_OBJECT

    private slots:

     void toUpper();

};

注意你需要包含 QTest头文件,并且测试函数必须声明为私有槽,这样测试框架才可以找到并执行他们。

然后你需要实现测试函数。实现看起来类似这样:

void TestQString::toUpper()

{

    QString str = ”Hello”;

    QVERIFY(str.toUpper() == ”HELLO”);

}

QVERIFY()宏将计算传入的表达式的值。如果为真,则测试函数继续进行;否则会向测试日志中增加一条描述错误的信息,并且该测试函数会停止执行。

但是如果需要向测试日志中增加更多的输出信息,你应该使用QCOMPARE() 宏。

void TestQString::toUpper()

{

    QString str = ”Hello”;

    QCOMPARE(str.toUpper(), QString(”HELLO”));

}

如果两个字符串不相等,他们的值都会追加到测试日志中,这样失败的原因就一目了然了。

最后,为使我们的测试程序能够单独执行,需要加入下列两行:

QTEST_MAIN(TestQString)

#include ”testqstring.moc”

QTEST_MAIN()宏将扩展成一个简单的main()函数,该main()函数会执行所有的测试函数。注意:如果测试类的声明和实现都在同一个cpp文件中,需要包含产生的moc文件,以使Qt的内省机制起作用。

执行测试程序

现在我们写完了测试程序,我们想执行它。假设我们将测试程序命名为testqstring.cpp并保存在一个空目录中:我们使用qmake生成一个工程文件和一个 makefile文件。

/myTestDirectory$ qmake -project ”QT += testlib”

(注意,文档中此处有误,这里应该是qmake -project ”CONF += qtestlib”)

/myTestDirectory$ qmake

/myTestDirectory$ make

注意:如果使用windows,将make换成nmake或者其它编译工具。运行生成的可执行文件,你会看到下列输出:

********* Start testing of TestQString *********

Config: Using QTest library 4.1.0, Qt 4.1.0

PASS : TestQString::initTestCase()

PASS : TestQString::toUpper()

PASS : TestQString::cleanupTestCase()

Totals: 3 passed, 0 failed, 0 skipped

********* Finished testing of TestQString *********

祝贺你!你刚刚编写并运行了第一个基于QTestLib框架的单元测试程序。


第二章 数据驱动测试

文件列表:

在这一章,我们将演示如何在不同的测试数据集上多次执行同一个测试程序。

到目前为止,我们都是采用硬编码的方式将测试数据写到测试函数中。如果我们增加更多的测试数据,那么测试函数会变成:

QCOMPARE(QString(”hello”).toUpper(), QString(”HELLO”));

QCOMPARE(QString(”Hello”).toUpper(), QString(”HELLO”));

QCOMPARE(QString(”HellO”).toUpper(), QString(”HELLO”));

QCOMPARE(QString(”HELLO”).toUpper(), QString(”HELLO”));

为了不使测试函数被重复的代码弄得凌乱不堪,QTestLib支持向测试函数增加测试数据。我们要做的,仅仅是向测试类增加另一个私有槽:

class TestQString: public QObject

{

Q_OBJECT

private slots:

void toUpper_data();

void toUpper();

};

编写提供测试数据的函数

一个为测试函数提供数据的函数必须与该测试函数同名,并加上_data后缀。我们的为测试函数提供数据的函数类似这样:

void TestQString::toUpper_data()

{

QTest::addColumn<QString>(”string”);

QTest::addColumn<QString>(”result”);

QTest::newRow(”all lower”) << ”hello” << ”HELLO”;

QTest::newRow(”mixed”) << ”Hello” << ”HELLO”;

QTest::newRow(”all upper”) << ”HELLO” << ”HELLO”;

}

首先,我们使用QTest::addColumn() 函数定义测试数据表的两列元素:测试字符串和在该测试字符串上调用QString::toUpper()函数期望得到的结果。

然后我们使用QTest::newRow()函数向测试数据表中增加一些数据。每组数据都会成为测试数据表中的一个单独的行。

QTest::newRow()函数接收一个参数:将要关联到该行测试数据的名字。如果测试函数执行失败,这个名字会被测试日志使用,以引用导致测试失败的数据。然后我们将测试数据加入到新行:首先是一个任意的字符串,然后是在该行字符串上调用QString::toUpper()函数期望得到的结果字符串。

可以将测试数据看作是一张二维表格。在这个例子里,它包含两列三行,列名为string 和result。另外,每行都会对应一个序号和名称。

index 
name 
string 
result

0
all lower    
hello 
HELLO

1
mixed 
Hello 
HELLO

2
all upper 
HELLO 
HELLO

重写测试函数

我们的测试函数可重写成:

void TestQString::toUpper()

{

   QFETCH(QString, string);

   QFETCH(QString, result);

   QCOMPARE(string.toUpper(), result);

}

QString::toUpper()函数会执行两次,对toUpper_data()函数向测试数据表中加入的每一行都会调用一次。

首先,我们调用QFETCH()宏从测试数据表中取出两个元素。QFETCH()接收两个参数:元素的数据类型和元素的名称。然后我们用QCOMPARE()宏执行测试操作。

使用这种方法可以不修改测试函数就向该函数加入新的数据。

同样,为使我们的测试程序能够单独执行,需要加入下列两行:

QTEST_MAIN(TestQString)

#include ”testqstring.moc”

像以前一样,QTEST_MAIN()宏将扩展成一个简单的main()函数,该main()函数会执行所有的测试函数。注意:如果测试类的声明和实现都在同一个cpp文件中,需要包含产生的moc文件,以使Qt的内省机制起作用。


第三章 模拟GUI事件

文件列表:

QTestLib特意为GUI测试提供了一些机制。QTestLib发送内部Qt事件,而不是模拟本地窗口系统事件,这就意味着运行测试程序不会对机器产生任何副作用。

在本章中,我们将会学习如何编写一个简单的针对GUI的测试程序。

编写一个针对GUI的测试程序

这一次,假设你想测试QLineEdit类。像以前一样,你需要一个类来包含测试程序:

#include <QtGui>

#include <QtTest/QtTest>

class TestGui: public QObject

{

Q_OBJECT

private slots:

void testGui();

};

唯一的区别是除了要加入QTest命名空间之外,你需要包含 QtGui类的定义。

void TestGui::testGui()

{

  QLineEdit lineEdit;

QTest::keyClicks(&lineEdit, ”hello world”);

   QCOMPARE(lineEdit.text()), QString(”hello world”));

}

在实现测试程序时,我们首先创建一个QLineEdit。然后我们调用QTest::keyClicks()函数模拟在行编辑框中输入”hello world”的动作。

注意:为了正确测试快捷键,控件必须显示出来。

QTest::keyClicks()在控件上模拟一连串的键盘敲击操作。另外,每次键盘敲击后,可以指定延迟时间(以毫秒为单位)。同样,你也可以用QTest::keyClick(),QTest::keyPress(),QTest::keyRelease(),QTest::mouseClick(),QTest::mouseDClick(),QTest::mouseMove(),QTest::mousePress()和 QTest::mouseRelease() 函数来模拟相应的GUI事件。

最后,我们使用QCOMPARE()宏来检验行编辑框的文本是否与预期的一致。

像以前一样,为使我们的测试程序能够单独执行,需要加入下列两行:

QTEST_MAIN(TestQString)

#include ”testqstring.moc”

像以前一样,QTEST_MAIN()宏将扩展成一个简单的main()函数,该main()函数会执行所有的测试函数。注意:如果测试类的声明和实现都在同一个cpp文件中,需要包含产生的moc文件,以使Qt的内省机制起作用。


第四章 重复GUI事件

文件列表:

在最后一章,我们将会演示如何模拟一个GUI事件、保存一系列GUI事件以及对一个控件重复触发GUI事件。

将一系列GUI事件保存起来并重复触发的方法与第二章描述的方法很类似。你所要做的只是向测试类增加一个提供测试数据的函数。

class TestGui: public QObject

{

    Q_OBJECT

    private slots:

    void testGui_data();

    void testGui();

};

编写提供测试数据的函数

像以前一样,一个为测试函数提供数据的函数必须与该测试函数同名,并加上_data后缀。

void TestGui::testGui_data()

{

QTest::addColumn<QTestEventList>(”events”);

     QTest::addColumn<QString>(”expected”);

QTestEventList list1;

list1.addKeyClick(‘a’);

QTest::newRow(”char”) << list1 << ”a”;

QTestEventList list2;

list2.addKeyClick(‘a’);

list2.addKeyClick(Qt::Key_Backspace);

QTest::newRow(”there and back again”) << list2 << ””;

}

首先,我们用QTest::addColumn() 函数定义测试数据表的元素:一个GUI事件列表,以及在控件上应用该事件列表预期得到的结果。注意第一个元素的类型是QTestEventList

QTestEventList可以保存将来要使用的GUI事件,并可以在任意控件上重复触发这些事件。

在目前的提供测试数据的函数中,我们创建了两个QTestEventList。第一个链表包括了一个敲击"a"键事件,我们调用QTestEventList::addKeyClick()函数向链表中加入该事件。然后我们用QTest::newRow()函数给该行数据指定一个名字,并把事件队列和期望结果输入到测试数据表中。

第二个链表包括两次键盘敲击:一个"a",然后是一个"backspace"。同样我们用QTestEventList::addKeyClick()函数将事件加入队列,用QTest::newRow()将事件队列和期望的结果加入测试数据表中,并为该行指定一个名字。

重写测试函数

我们的测试函数可重写成:

void TestGui::testGui()

{

    QFETCH(QTestEventList, events);

QFETCH(QString, expected);

QLineEdit lineEdit;

events.simulate(&lineEdit);

QCOMPARE(lineEdit.text(), expected);

}

TestGui::testGui()函数会执行两次,对在TestGui::testGui_data()函数中创建的每一行测试数据都执行一次。

首先,我们用QFETCH() 宏从测试数据集中取出两个元素。QFETCH() 宏接收两个参数:元素的数据类型和元素的名字。然后我们创建了一个QLineEdit,调用QTestEventList::simulate()函数在控件上触发事件队列。

最后,我们用QCOMPARE()宏检测行编辑框的内容是否与我们期望的一致。

像以前一样,为使我们的测试程序能够单独执行,需要加入下列两行:

QTEST_MAIN(TestQString)

#include ”testqstring.moc”

像以前一样,QTEST_MAIN()宏将扩展成一个简单的main()函数,该main()函数会执行所有的测试函数。注意:如果测试类的声明和实现都在同一个cpp文件中,需要包含产生的moc文件,以使Qt的内省机制起作用。

QTestLib Tutorial的更多相关文章

  1. QTestlib Manual翻译

    Trolltech公司提供的QTestlib框架,是一种针对基于QT编写的程序或库的单元测试工具.QTestLib提供了单元测试框架的基本功能,并提供了针对GUI测试的扩展功能. 目录: QtestL ...

  2. [翻译+山寨]Hangfire Highlighter Tutorial

    前言 Hangfire是一个开源且商业免费使用的工具函数库.可以让你非常容易地在ASP.NET应用(也可以不在ASP.NET应用)中执行多种类型的后台任务,而无需自行定制开发和管理基于Windows ...

  3. Django 1.7 Tutorial 学习笔记

    官方教程在这里 : Here 写在前面的废话:)) 以前学习新东西,第一想到的是找本入门教程,按照书上做一遍.现在看了各种网上的入门教程后,我觉得还是看官方Tutorial靠谱.书的弊端一说一大推 本 ...

  4. thrift 服务端linux C ++ 与客户端 windows python 环境配置(thrift 自带tutorial为例)

    关于Thrift文档化的确是做的不好.摸索了很久才终于把跨linux与windows跨C++与python语言的配置成功完成.以下是步骤: 1)                 Linux下环境配置 ...

  5. Hive Tutorial(上)(Hive 入门指导)

    用户指导 Hive 指导 Hive指导 概念 Hive是什么 Hive不是什么 获得和开始 数据单元 类型系统 内置操作符和方法 语言性能 用法和例子(在<下>里面) 概念 Hive是什么 ...

  6. Home / Python MySQL Tutorial / Calling MySQL Stored Procedures in Python Calling MySQL Stored Procedures in Python

    f you are not familiar with MySQL stored procedures or want to review it as a refresher, you can fol ...

  7. Using FreeMarker templates (FTL)- Tutorial

    Lars Vogel, (c) 2012, 2016 vogella GmbHVersion 1.4,06.10.2016 Table of Contents 1. Introduction to F ...

  8. Oracle Forms 10g Tutorial Ebook Download - Oracle Forms Blog

    A step by step tutorial for Oracle Forms 10g development. This guide is helpful for freshers in Orac ...

  9. Tutorial - Deferred Rendering Shadow Mapping 转

    http://www.codinglabs.net/tutorial_opengl_deferred_rendering_shadow_mapping.aspx Tutorial - Deferred ...

随机推荐

  1. IOS 中关于自定义Cell 上的按钮 开关等点击事件的实现方法(代理)

    1.在自定义的Cell .h文件中写出代理,写出代理方法. @protocol selectButtonDelegate <NSObject> -(void)selectModelID:( ...

  2. Reading source code

    software is a system built up of many parts rebuild that decomposition see the patterns in codes is ...

  3. 使用myfocus制作焦点图

    第一步:引入myfocus基本库和所要使用样式的js和css文件 <script src="js/myfocus-2.0.1.min.js"></script&g ...

  4. 解决: AGPBI: {"kind":"error","text":"indicate that it is *not* an inner class.","sources":[{}]}

    关于Gradle Console输出类似这样错误信息: AGPBI: {"kind":"error","text":"indica ...

  5. java使用dom4j和XPath解析XML与.net 操作XML小结

    最近研究java的dom4j包,使用 dom4j包来操作了xml 文件 包括三个文件:studentInfo.xml(待解析的xml文件), Dom4jReadExmple.java(解析的主要类), ...

  6. commons-logging 和 log4j 之间的关系

    我们在做项目时,日志的记录是必不可少的一项任务,而我们通常是使用 apache 的 log4j 日志管理工具.然而,在项目中,我们经常会看到两个 jar 包:commons-logging.jar 和 ...

  7. python成长之路第三篇(4)_作用域,递归,模块,内置模块(os,ConfigParser,hashlib),with文件操作

    打个广告欢迎加入linux,python资源分享群群号:478616847 目录: 1.作用域 2.递归 3.模块介绍 4.内置模块-OS 5.内置模块-ConfigParser 6.内置模块-has ...

  8. python3.4 伪装成浏览器获取页面信息失败

    最近学了下网络爬虫,打算从一个网站上提取点东西,自己练练手,刚开始还从这个网站上取了正确的html,后来百般尝试还是不能取正确的html,希望能得到大家的帮助~ 我刚开始的代码是: 1 url=&qu ...

  9. Android jar包混淆

    具体可参考http://proguard.sourceforge.net/manual/examples.html#library 1.找到android的adt目录下的 D:\soft\adt-bu ...

  10. codecomb 2091【路径数量】

    好久没有更新博客了啊……屯了一堆题没发呢 这是丧心病狂的hzwer每日NOI模拟赛第一天的第一题 妈蛋说好的NOIP难度图论算法两题网络流!让我说什么好 唔……codecomb的页面在晚上就会变得很奇 ...