基于HTML5的应用开发与测试指南
1. HTML5应用开发
在开发HTML5应用时,我们可以借助一些技术和工具来实现特定的功能。下面以一个地震信息展示应用为例,介绍具体的开发步骤。
1.1 创建手风琴组件
首先,我们需要实例化一个新的
Nokia.Accordion
对象。代码如下:
Nokia.use('template-default', 'accordion', init);
这个代码的作用是将之前设置的
div id = 'accordion'
的
<div>
元素作为手风琴组件的容器。同时,还可以通过其他选项来配置该组件的各种属性,例如设置是否可折叠等。每个组件都有自己的配置选项,具体可参考相关文档。
1.2 获取和解析数据
接下来,我们要从美国地质调查局(USGS)下载并解析XML数据。可以使用
XmlHttpRequest
来请求XML数据,然后用简单的JavaScript代码解析结果并进行HTML格式化,最后将数据插入到手风琴组件中。
示例代码基于Nokia Aptana插件中的一个RSS阅读器示例。值得一提的是,从USGS XML提要中获取的摘要标记包含一个
<img>
标签,无需进行复杂的编码或图像处理,每个地震的摘要信息除了文本细节外,还会显示该地震位置的缩略图。我们只需直接粘贴从USGS获取的
<img>
标签即可正常显示图像。
1.3 添加HTML5特效
为了让应用更生动,我们可以使用HTML5的一些特性。在图像元素中添加类声明:
class='quakeImage'
然后在CSS文件中添加以下声明块:
.quakeImage:active {
-webkit-transition: all 1s ease-in-out;
-webkit-transform: scale(5) translateX(50px);
}
这样,当点击图像时,图像会使用
-webkit-transform
属性进行放大并向右移动,实现一个简单的缩放效果。
1.4 打包应用
最后,将应用打包成混合应用。为了避免安装文件的麻烦,我们将内容作为资源进行打包和安装。
2. 应用测试
在应用开发接近完成时,测试是确保应用质量的重要环节。下面介绍一些测试的方法和工具。
2.1 测试准备
在进行测试之前,需要制定一个测试计划。测试计划应包含一系列测试用例,每个测试用例要描述初始配置、测试步骤和预期结果。通过测试计划和调查工作,可以了解应用功能的可测试性以及可自动化测试的比例。
测试可分为功能测试和非功能测试:
-
功能测试
:涉及应用的实际操作,如业务逻辑的正确性。
-
非功能测试
:关注应用在正常操作之外的性能,如内存不足、信号丢失、GPS定位丢失、服务器不可用等情况。非功能测试也常被称为对抗性测试,在测试计划中应至少包含与功能测试相同比例的对抗性测试。
常见的测试类型包括动态测试和静态测试:
-
动态测试
:在应用运行时进行,包括手动测试、单元测试、集成测试和使用分析工具(如valgrind,但Symbian系统不可用)。
-
静态测试
:对源代码进行非执行性检查,如代码审查。编译器警告也是一种简单的静态测试工具,应采用零警告的代码策略。
为了确保应用的正确性,还可以采取以下措施:
-
每日构建
:从变更控制系统中每日构建应用,并进行冒烟测试,若发现问题则停止开发,找出根本原因并修复。
-
伙伴审查
:与伙伴一起审查提交到变更仓库的代码,有助于发现明显和隐蔽的编码错误。
-
编译器警告
:重视编译器警告,采用零警告策略。
-
使用多个编译器
:在跨平台开发时,可使用不同供应商的编译器,如在模拟器测试时使用Microsoft Visual Studio,在设备编译时使用其他编译器。
-
尽早在设备上运行
:移动应用开发应经常在硬件设备上运行应用,以了解其实际性能。
2.2 使用Qt的测试框架
Qt提供了一个名为QTest的测试框架,用于实现对使用Qt的类进行单元测试。QTest是一个小型、自包含的库,可以调用自定义类中的测试方法,对应用组件进行测试。
QTest的测试运行器使用Qt的元对象协议来内省提供的类中的方法,确定运行时的操作。只需提供一个从
QObject
派生的类,并定义实现测试的槽函数即可。QTest会以特殊方式处理测试类中的几个槽函数,以控制测试环境的设置和清理:
-
initTestCase
:在所有测试运行之前调用。
-
cleanupTestCase
:在所有测试运行之后调用。
-
init
:在每个测试运行之前调用。
-
cleanup
:在每个测试运行之后调用。
下面是一个简单的测试类示例:
#include <QtTest/QtTest>
class TrivialTest: public QObject
{
Q_OBJECT
private slots:
void trivialTest()
{ QVERIFY(1 == 1); }
void anotherTrivialTest()
{ QVERIFY(0 != 1); }
};
QTEST_MAIN(TrivialTest)
#include "trivialtest.moc"
在这个示例中,
QVERIFY
宏用于验证条件是否为真,如果条件不成立则测试失败。
如果有
qmake
可执行文件,可以使用以下命令创建一个QTest测试类的
.pro
文件:
C:\Book\Tests>qmake –project “CONFIG += QTest”
C:\Book\Tests>qmake
C:\Book\Tests>make
如果没有
qmake
,也可以在Nokia Qt SDK中使用Qt Creator创建:
1. 选择 “File>New File or Project”…
2. 从出现窗口的左上角窗格中选择 “Other Project”。
3. 从右上角列表中选择 “Qt Unit Test”。
4. 点击 “Choose…”
5. 输入单元测试的名称和路径,然后点击 “Next”。
6. 至少选择Simulator Qt选项作为构建系统,也可选择设备目标,然后点击 “Next”。
7. 选择单元测试依赖的模块,如用于网络的
QtNetwork
,然后点击 “Next”。
8. 填写描述第一个单元测试的表单,然后点击 “Next”。
9. 点击 “Finish”。
QTest还提供了其他几个宏来辅助测试,如下表所示:
| 宏 | 作用 |
| ---- | ---- |
|
QVERIFY
| 验证条件为真,若不成立则测试失败 |
|
QVERIFY2
| 与
QVERIFY
类似,但在条件失败时输出详细信息 |
|
QCOMPARE
| 对实际值和预期值进行类型安全的比较,对于浮点数使用
qFuzzyCompare
进行近似比较 |
|
QSKIP
| 停止当前测试的执行,不将其标记为失败,但会记录跳过原因 |
|
QBENCHMARK
| 对紧随其后的代码块进行基准测试,必要时多次运行以获取基准数据 |
|
QBENCHMARK_ONCE
| 只运行一次基准测试代码块,但执行时间过短时可能报告为零 |
2.3 单元测试示例
下面以
QuakeEvent
类的单元测试为例,展示如何使用QTest进行单元测试。
#include <QtCore/QString>
#include <QtTest/QtTest>
#include <QDebug>
#include "quakeevent.h"
class TestQuakeEvent : public QObject
{
Q_OBJECT
public:
TestQuakeEvent();
private:
QuakeEvent *mEvent;
private Q_SLOTS:
void initTestCase();
void cleanupTestCase();
void init();
void cleanup();
void testConstructor();
void testSetGet();
void testIsEmpty();
void testClear();
void testComparator();
void testId();
void testSummary();
void testWhen();
void testWhere();
void testMagnitude();
void testPosition();
void testElevation();
void testHtml();
void testDistanceTo();
};
TestQuakeEvent::TestQuakeEvent()
{
}
void TestQuakeEvent::initTestCase() {
mEvent = new QuakeEvent();
}
void TestQuakeEvent::cleanupTestCase() {
delete mEvent;
}
void TestQuakeEvent::init() {
mEvent->clear();
mEvent->set("title", "M 2.6, Hawaii region, Hawaii");
mEvent->set("point", "19.9770 -156.8687");
mEvent->set("elev", "-7900");
mEvent->set("summary", "<img src=\"http://earthquake.usgs.gov¬
/images/globes/20_-155.jpg\" alt=\"19.977°N 156.869°W\"¬
align=\"left\" hspace=\"20\" /><p>Monday, September 6, 2010 15:¬
19:09 UTC<br>Monday, September 6, 2010 05:19:09 AM at epicenter<¬
/p><p><strong>Depth</strong>: 7.90 km (4.91 mi)</p>");
}
void TestQuakeEvent::cleanup() {
mEvent->clear();
}
void TestQuakeEvent::testConstructor() {
QuakeEvent *e = new QuakeEvent();
QVERIFY(e->isEmpty());
delete e;
}
void TestQuakeEvent::testSetGet() {
mEvent->set("arbitrary", "value");
QVERIFY(mEvent->get("arbitrary")=="value");
}
// Failures may indicate a problem with either
// isEmpty or clear
void TestQuakeEvent::testIsEmpty() {
QVERIFY(!mEvent->isEmpty());
mEvent->clear();
QVERIFY(mEvent->isEmpty());
}
// Failures may indicate a problem with either
// isEmpty or clear
void TestQuakeEvent::testClear() {
QVERIFY(!mEvent->isEmpty());
mEvent->clear();
QVERIFY(mEvent->isEmpty());
}
void TestQuakeEvent::testComparator() {
QuakeEvent *e = new QuakeEvent();
e->set("summary", "<img src=\"http://earthquake.usgs.gov¬
/images/globes/20_-155.jpg\" alt=\"19.977°N 156.869°W\"¬
align=\"left\" hspace=\"20\" /><p>Monday, September 6, 2010 15:¬
19:09 UTC<br>Monday, September 6, 2010 05:19:09 AM at epicenter<¬
/p><p><strong>Depth</strong>: 7.90 km (4.91 mi)</p>");
QVERIFY(*mEvent < *e);
delete e;
}
void TestQuakeEvent::testId() {
mEvent->set("arbitrary", "123456789");
QVERIFY(mEvent->get("arbitrary")=="123456789");
}
void TestQuakeEvent::testSummary() {
QVERIFY(mEvent->summary() == "M 2.6, Hawaii region, Hawaii");
}
void TestQuakeEvent::testWhen() {
// Ideally this would test a number of dates and times
QDateTime when(QDate(2010, 9, 6),
QTime( 15, 19, 9), Qt::UTC);
QVERIFY(mEvent->when() == when);
}
void TestQuakeEvent::testWhere() {
QVERIFY(mEvent->where() == "Hawaii region, Hawaii");
}
void TestQuakeEvent::testMagnitude() {
float mag = (float)mEvent->magnitude();
QCOMPARE(mag, (float)2.60);
}
void TestQuakeEvent::testPosition() {
qDebug() << mEvent->position();
QCOMPARE((float)mEvent->position().first, (float)19.977);
QCOMPARE((float)mEvent->position().second, (float)-156.869);
}
void TestQuakeEvent::testElevation() {
QVERIFY(qFuzzyCompare(mEvent->elevation(), -7900.0));
}
void TestQuakeEvent::testHtml() {
QVERIFY(mEvent->html() ==
"<img src=\"http://earthquake.usgs.gov¬
/images/globes/20_-155.jpg\" alt=\"19.977°N 156.869°W\"¬
align=\"left\" hspace=\"20\" /><p>Monday, September 6, 2010 15:¬
19:09 UTC<br>Monday, September 6, 2010 05:19:09 AM at epicenter<¬
/p><p><strong>Depth</strong>: 7.90 km (4.91 mi)</p>");
}
这个单元测试类对
QuakeEvent
类的各个方法进行了测试,确保其功能的正确性。
通过以上步骤,我们可以完成一个基于HTML5的应用开发,并使用QTest框架对应用进行全面的测试,从而提高应用的质量和稳定性。
基于HTML5的应用开发与测试指南
3. 测试流程总结
为了更清晰地展示整个测试过程,我们可以用mermaid格式的流程图来表示:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px
A([开始]):::startend --> B(制定测试计划):::process
B --> C{选择测试类型}:::decision
C -->|功能测试| D(测试业务逻辑):::process
C -->|非功能测试| E(模拟异常情况):::process
D --> F(执行测试用例):::process
E --> F
F --> G{测试是否通过}:::decision
G -->|是| H(结束测试):::process
G -->|否| I(定位问题):::process
I --> J(修复问题):::process
J --> B
H --> K([结束]):::startend
从这个流程图可以看出,测试是一个循环的过程。首先要制定详细的测试计划,然后根据应用的需求选择合适的测试类型,执行测试用例后判断是否通过。如果测试不通过,需要定位问题并修复,然后重新进行测试,直到所有测试用例都通过为止。
4. 常见问题及解决方法
在应用开发和测试过程中,可能会遇到一些常见的问题,下面我们来分析这些问题并给出相应的解决方法。
| 问题 | 描述 | 解决方法 |
|---|---|---|
| 编译器警告 | 在Symbian构建环境编译时可能会出现大量警告,影响零警告策略的实施 | 可以使用编译器pragma来关闭某些警告,或者定期(如每天)查看警告信息,确保没有新问题出现。如果项目文件数量稳定,可以捕获输出并使用diff工具验证警告是否保持一致 |
| 模拟器与设备表现不一致 | 模拟器只能模拟设备环境,实际在设备上运行时可能会出现性能或功能上的差异 | 尽早并经常在设备上运行应用,以了解其实际性能。模拟器可以用于快速迭代用户界面,但不能替代在真实设备上的测试 |
| 测试用例覆盖不全 | 可能会遗漏某些功能或异常情况的测试 | 制定全面的测试计划,充分考虑功能测试和非功能测试的各个方面。可以通过代码审查和分析工具来辅助发现潜在的测试点 |
5. 总结
通过本文的介绍,我们了解了基于HTML5的应用开发和测试的全过程。在开发方面,我们学习了如何创建手风琴组件、获取和解析数据、添加HTML5特效以及打包应用。在测试方面,我们掌握了测试的准备工作、使用Qt的QTest框架进行单元测试的方法,以及如何处理常见的问题。
在实际开发中,我们应该重视测试工作,采用科学的测试方法和工具,确保应用的质量和稳定性。同时,要不断学习和掌握新的技术和方法,以适应不断变化的开发环境和用户需求。希望本文对大家在HTML5应用开发和测试方面有所帮助。
超级会员免费看
6万+

被折叠的 条评论
为什么被折叠?



