使用 CasperJS 进行简单的 UI 测试 已翻译 100%

oschina 投递于 2013/06/07 10:05 (共 14 段, 翻译完成于 06-12)
阅读 8427
收藏 69
6
加载中

摘要

无论你开发大或小的应用, 从安全来讲测试是一个很重要的组成部分.

但是如何可靠持续的测试, 尤其是当你的人员不能有效的测试应用的每一次改变? 所以呢,把这个工作交给软件是最合适的了.

这么多年来, 开发者开发了很多应用和技术来满足这个需求. 当然, 它们运行的非常好. 但是我们总是寻找更新的, 更简单的 (有时候是更'酷'的) 方式来做我们的工作. 所以最近我开始学习一种更有前途的新技术: PhantomJS.

-V-
-V-
翻译于 2013/06/07 11:30
1

PhantomJS是什么?
PhantomJS 是一个无界面的,包含了WebKit浏览器引擎和JavaScript API的脚本解释器. 速度快并且支持各种web标准: DOM 操作, CSS 选择器, JSON, Canvas 和SVG.

PhantomJS 的创建者是 Ariya Hidayat. 它是一个非常棒的技术,但是通过网站上的了解和所有的APIs文档, 我遇到了 CasperJS.

CasperJS是什么?
Casper 是一个用JavaScript编写的基于PhantomJS的导航脚本和测试工具.它充许我们像PHPUnit或 JUnit一样测试我们的网站,测试我们的代码.

它是一个非常棒的工具 – 一是它是非常简单的,用JavaScript编写,满足各种各样的测试需求,一是它可以方便的和我们的开发环境集成. 完美的组合前端和后端.

-V-
-V-
翻译于 2013/06/09 15:27
1

在本篇文章中,我将浏览一下CasperJS的基础用法。我将扮演一个典型的用户访问New Relic(新的遗址)网站的一页,特别是‘真实用户监控’部分。

我之所以选择这一页是因为它有大量方面对一个标准网站或应用极为常见,如图像,表单,按钮,链接和文本。它内容丰富并且有许多东西可供我们处理与测试。现在,我确信New Relic的勤快的伙计已经做过这些,但我也非常相信他们不会介意我为这个网站建立一个简单的测试集和断言。

特征

CasperJS具有一系列特征。 本文中,我会聚焦于 测试人员 API。它具有一些列功能与断言,都是你期望一个好的测试API所具有的,包括:

* assertTextExists (文本存在断言)
* assertTitle (标题断言)
* assertHttpStatus (HTTP状态断言)
* assertDoesntExist (不存在断言)
* assertUrlMatch (Url匹配断言)

super0555
super0555
翻译于 2013/06/10 09:03
1

我将使用这些断言来显示CasperJS是如何工作的。它也包含一组其他特性,但我不会去深入探讨——仅仅足够做一个工作示例而已。不过,我鼓励你研究一下精彩的在线API文档。它阅读起来令人愉悦,因为它相当清晰和简洁。

准备
如果你没有准备好,在我们继续以前,先安装 PhantomJSCasper 。 现在,让我们马上开始吧。

开始

当我第一次加载New Relic网站的'真实用户监控'页面,看起来像下面图片这样(自撰写本文以后它已经变化了)。我突出了注册表格的起点。

New-Relic-partial-form_

super0555
super0555
翻译于 2013/06/10 09:15
1

如果你点击了这个表单里的任何元素,它其余的部分就会显露出来,看起来就是下图这样。

nerd-in-tshirt-form

测试将着眼于表单,但我们也要看看title标签,表单左边的图片,及其上的文字。

代码:
首先,为节省时间,我初始化了两个变量:一个用来存储URL,一个用来存储网站名称,因为我要在测试中的‘success’信息里显示它们。

var url = 'http://newrelic.com/product/real-user-monitoring';
var siteName = 'NewRelic';

Casper带有4个内建记录级别:

* debug
* info
* warning
* error

赵亮-碧海情天
赵亮-碧海情天
翻译于 2013/06/07 17:16
1
默认情况下,CasperJS会在‘error’级别过滤日志。所以如果你开始记录日志后没有看到任何东西,可能就是这个原因。为确保显示日志输出,我把它设置为‘debug’。而且我关闭了‘verbose’选项,如果它激活,我们会看到关于所有东西的信息,这会相当干扰。
var casper = require('casper').create({
    verbose: false,
    logLevel: 'debug'
});

你可以在Casper API页面上发现其它配置选项。comment函数,如下面演示的,使我们能记录输出——在这种情况下是输出到控制台。我在这里使用一个简单的消息说明测试开始了:

casper.test.comment('Starting Testing');

函数‘casper.start’开始运行测试:

casper.start(url, function() {
    this.test.assert(
        this.getCurrentUrl() === url, 'url is the one expected'
    );
 
    this.test.assertHttpStatus(200, siteName + ' is up');
赵亮-碧海情天
赵亮-碧海情天
翻译于 2013/06/08 19:54
1

这是我所做的:我加载在‘url’中指定的URL,并假定我们可以载入想要的网址。在成功加载页面之后,开始调用一些断言来确认所载入的页面上的内容是我们所期望的。

在这种情况下,我对返回的状态码进行了一个快速检查,它应该是200,我得到的也是200。让我们进行另一个断言:

this.test.assertTitle(
    'Real User Monitoring, End User Experience Monitoring : New Relic',
    siteName + ' has the correct title'
);

上面这个测试非常简单。它断言载入的页面的标题应该是什么,并输出一个含有该信息的消息。

在下面的代码里,我首先检查确认存在一个ID为‘nr-signup-form’的表单。如果这个表单不存在,那对表单内的元素进行检查就没有意义了,对吧?

this.test.assertExists(
    'form[id="nr-signup-form"]',
    siteName + ' has a form with name "nr-signup-form"'
);

现在,在我继续之前,我要提到的是,当我断言元素存在或不存在于加载的页面上时,我可以用两种不同的方法:

* XPath
* CSS选择器

赵亮-碧海情天
赵亮-碧海情天
翻译于 2013/06/12 14:22
1

如果你想要更多XPath的信息,请检阅后面‘延伸阅读’部分中的一些相关链接,或阅读 我写并发到maltblue的文章。CSS选择器应该有很好的自我解释性。但为以防万一,我在“延伸阅读”部分中同样包含了关于它的链接。

现在让我们用断言来搜索输入域控件:

this.test.assertExists(
    {type: 'xpath', path: '//input[@id="FullName"]' },
    'the element exists'
);
 
this.test.assertExists(
    {type: 'xpath', path: '//input[@id="Company"]' },
    'the element exists'
);
 
this.test.assertExists(
    {type: 'xpath', path: '//input[@id="Email"]' },
                'the element exists'
);
 
this.test.assertExists(
    {type: 'xpath', path: '//input[@id="Password"]' },
    'the element exists'
);
 
this.test.assertExists(
    {type: 'xpath', path: '//input[@id="PromoCode"]' },
    'the element exists'
);

在上面的五个断言中,我查找了五个输入域控件,它们的ID分别是‘FullName’, ‘Company’, ‘Email’, ‘Password’ 和‘PromoCode’。用XPath查找选择列表控件元素同样容易。

在下面的测试中,我假定有四个选择列表控件,它们的ID分别是:‘country’, ‘group’, ‘company_size’ 和‘HostEstimate’。

this.test.assertExists(
    {type: 'xpath', path: '//select[@id="country"]' },
    'the element exists'
);
 
this.test.assertExists(
    {type: 'xpath', path: '//select[@id="group"]' },
    'the element exists'
);
 
this.test.assertExists(
    {type: 'xpath', path: '//select[@id="company_size"]' },
    'the element exists'
);
 
this.test.assertExists(
    {type: 'xpath', path: '//select[@id="HostEstimate"]' },
    'the element exists'
);

现在,这些测试还非常简单。那么,让我们来把它们变得复杂点。

this.test.assertExists(
    {
        type: 'xpath',
        path: '//button[@id="sign-up-button"
                and @class="small-button"
                and @type="submit"]'
    }, 'the element exists'
);
赵亮-碧海情天
赵亮-碧海情天
翻译于 2013/06/12 14:37
1
在上面的测试中,我搜索‘Create Free Account’按钮,它在页面中的位置如下图所示。

create-free-account-highlighted

我在查询中使用了一些条件运算符。我们要寻找一个具有下列条件的按钮:

* ID 为 ‘sign-up-button’
* class 为‘small-button’
* type 为‘submit’

虽然看起来似乎我关注XPath比CasperJS更多,但为了更多的功能和配置,请耐心忍受我多说一点吧。

var x = require('casper').selectXPath;
var checkboxXpath = "//input[@type='checkbox' and
@id='checkbox1']/parent::*/a/label[
    contains(., 'Java') or
    contains(., 'Python') or
    contains(., 'Ruby') or
    contains(., 'PHP') or
    contains(., '.NET') or
    contains(., 'Node.js')
]";
this.test.assertExists(x(checkboxXpath), 'the element exists');

我在上面的测试中所做的,是通过把'x'初始化为‘selectXPath’助手来使XPath测试变得简化一点。我要查找那一页上所有选择应用程序类型的复选框,所以XPath查询查找复选框时用一个伴随的label标签来匹配所提供的应用程序语言的名称。

赵亮-碧海情天
赵亮-碧海情天
翻译于 2013/06/12 16:32
1

为专门显示我并非只会使用XPath(虽然它极其强大而且简单),下面的两个测试也使用CSS选择器来检查一个输入域控件和列表项目也存在。

this.test.assertVisible('input#Company');
 
this.test.assertExists('li.nav-enterprise', 'the element exists');

搜索表单元素和列表项目很简单,但若你的页面有很多资源,对于图片或Flash的载入又怎么检测呢?这有一个例子:

this.test.assertResourceExists(
    '/images/tshirt-dude-form.png', 'T-shirt Image exists'
);

对于上面的测试,我断言穿着所展示T恤的男人的照片已载入。 最后一个测试断言某些文本存在,在本情况中就是在穿着T恤的男人镜头上方的‘Sign up for free!’文本:

    this.test.assertTextExists(
        'Sign up for free!', 'page body contains "Sign up for free!"'
    );
 
});

然后我们这样结束‘start’函数:

casper.test.comment('Ending Testing');

测试基本完成了,所以我输出另一个日志记录来让用户知道这一点:

casper.run(function() {
    this.test.done(16);
    this.echo('So the whole suite ended.');
    require('utils').dump(casper.test.getFailures());
    require('utils').dump(casper.test.getPasses());
    this.exit();
});

我可以写出我想要的所有测试,但若不调用“run”则什么都不会发生。所以“run”是揭开上述工作的序幕。我所做的是检查脚本是否已经运行了16个测试,并且在最后用‘this.echo()’输出最后一行文字表示整个测试已结束。

赵亮-碧海情天
赵亮-碧海情天
翻译于 2013/06/12 17:00
1
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(9)

lkiarest
lkiarest
是的,模拟用户操作根本没提及,忽悠人的吧
陈纪年
陈纪年
整篇文章这么大篇幅写“判断页面上某个元素存不存在”,这个……我用jQuery选择器就可以做到了……其实更想看到的是模拟用户行为进行测试什么的,而为了这些太简单的UI测试,编写这么多的测试代码,反而觉得没什么必要。
红薯
红薯

引用来自“daxiaoming”的评论

看来翻译的大牛都隐身了啊,机器翻译大行其道。

有些英文原文写得一般,翻译的效果也会差很多的。不过技术文章,大概的意思能看懂就好了:)
gaubee
gaubee
美看懂亮点在哪里……
limichange
limichange
还是手动编写比较好,有什么改动就直接改了。
daxiaoming
daxiaoming
看来翻译的大牛都隐身了啊,机器翻译大行其道。
junsun
junsun
mark
唐昌林
这样去测试,成本好高呀。为了测试,需要编写测试脚本、调试测试脚本、正式执行脚本,如果页面稍微改动,还得重复这样的步骤
菇娘不要怕嘛
菇娘不要怕嘛
这个不错~~~~
返回顶部
顶部