本文从前端测试工具 TestCafe 的测试代码结构入手,介绍用法。
Mocha 的测试代码结构
首先来看较常见的 mocha 的基本代码结构,由外层的 describe
和内层的 it
组成,例如下面的代码:
describe('用例集名称', function() {
it('单条用例1', function() {
// ...
});
it('单条用例2', function() {
// ...
});
});
其中 describe
相当于用例集, it
相当于单条用例,多条 it
包含在 describe
函数的第二个参数函数中依次调用。TestCafe 测试代码结构与此类似,但也有区别。
TestCafe 的测试代码结构
TestCafe 中,对应 describe
的是 fixture
,对应 it
的是 test
,而且在代码层面,取消了嵌套关系。 如下:
fixture('用例集名称');
test('单条用例1', async t => {
/* Test 1 Code */
});
test('单条用例2', async t => {
/* Test 2 Code */
});
在 mocha 的describe/it 结构 中,同一个 describe 下的 每个 it 是顺序执行的。
所以上一个 it
如果修改了外部测试环境,会影响到后面 it
的结果,将导致无法预测的结果。所以这种测试结构适合各个 it
不相关的情况。
与此不同的是,在 TestCafe 中,每个 fixture
下的 test
执行结束后,会重新回到 fixture
规定的状态,如图:
这就体现了 fixture
的含义,见 下节 详细介绍。
fixture 的含义
首先我们需要清楚,一般意义上的测试活动都包含三个阶段:
- 将被测物(DUT,Device Under Test 的缩写)置于某种状态
- 采取某种行动
- 检查被测物的新状态是否符合预期
这三个阶段中,实现第一阶段的是 fixture,中文含义是"夹具、固定装置":
在各类测试中(不仅仅是软件测试),都有 fixture 的 身影。fixture 的作用是:
- 预先设置被测物的运行环境
- 将被测物的指标、状态调节到规定的状态。
设置fixture的好处,第一是可重复,方便连续重复测试多个物件,第二是方便参数化,可以在多种参数环境下反复测试。下面列一些形象的例子便于理解:
例子1:考试中的考场,将教室中无关物品清除、设置好规定的桌椅器材,便于被测物(考生)通过测试。在下一场考试开始前,考场将会被恢复到同样的状态。标准化的考场才能让各地考生的成绩有可比性。
例子2:运动会的赛场,裁判、场地、器材共同决定了比赛的环境,标准化的赛场才能让各届运动会的运动成绩有可比性。
例子3:汽车生产线中,整车下线前的最后一步,汽车将通过道路模拟机,测试转动、振动等指标,而且可以调整多种参数,以模拟各种道路情况。标准化的道路模拟才能保证汽车产品的一致性。
从另一个角度理解 fixture
虽然代码里的 fixture
写在最前面,似乎是先有 fixture
再有 test
。其实应该这么理解: test
是测试的核心,一些有共同初始条件的test,将这些条件提取出来,成为 fixture
,起到辅助作用。
比如下图中,一些有共同初始条件的 test
,用红绿颜色表示
将初始条件提取出来,放在同一个 fixture
中。
经过这样一次抽象,减少了冗余代码,方便维护和扩展代码。
再拿考场做例子,英语听力考试中,每位考生都需要听声音,于是在考场中布置音响设备,让每位考生都听到声音。而体育测验中需要跑道,就把全部考生放在运动场上测验。
TestCafe 中的 fixture
在 TestCafe 中,调用一次 fixture()
即声明了一个fixture:
fixture(fixtureName)
fixture
支持的方法有:
.page() // 设置页面
.meta() //设置元信息
.before(async ctx => {}) // 测试钩子
.after(async ctx => {})
.beforeEach(async t => {})
.afterEach(async t => {})
TestCafe 中的 Server 和 Client
我们在 上文中提到过 ,TestCafe的特点在于新增了一个URL代理,在测试脚本和页面中起到中介作用,所以产生了服务侧(Server side) 和 客户端侧(Client side)的概念,如下图:
URL代理就是服务侧,编写的测试代码都是运行在服务侧。提供服务端的好处是,可以将测试代码与测试浏览器分离,运行在不同的主机上,比如 这篇文章 里提到的远程浏览器,访问服务端,一样能执行自动测试。
TestCafe 中的 Test Controller
常规的测试工具中,比如 Puppeteer 和 selenium,页面操作都是零散的单条语句执行,如下图
观察 Puppeteer 和 selenium 提供的接口即可以看出,测试动作都是由比较底层的对象发出(比如 Puppeteer 中的 page 对象,和 selenium 中的 driver 对象):
//Puppeteer
browser = await puppeteer.launch()
page = await browser.newPage()
await page.goto("https://www.google.com")
element = await page.waitForSelector('#q')
//selenium
WebDriver driver = new FirefoxDriver();
driver.get("https://www.google.com");
WebElement element = driver.findElement(By.name("q"));
与之相比,Test Cafe 提供了 Test Controller 的角色,可以看做是一个代理人,集中执行所有页面动作(比如寻找元素、输入文字、等待页面变化、校验数据)。在 服务侧 代码中,页面动作都封装为 Test Controller 的执行方法,而不再是零散的页面动作。
这样写出的用例就像操作者真实的操作页面,更加易读。下一节 将介绍具体的 Test Controller 的写法。
TestCafe 中的 Test
TestCafe 的 单个用例使用 test
函数调用,负责执行服务侧代码、发出页面动作。而且如 上节 中的介绍,所有的动作都由 Test Controller 执行,所以 test
函数的参数是一个以 Test Controller 为参数的函数,变量名约定为 t
。
test('Test Case', t => {});
对比 Mocha的测试代码就能看出区别,这里的执行函数是没有参数的: ()
//Mocha
it('Test Case', () => {});
比如,下面的例子中,测试动作统一由 Test Controller t
发出:
test('My Test', async t => {
await t
.click('#populate')
.click('#submit-button');
});
TestCafe 中筛选运行集
与 mocha 的describe/it 结构 类似,在TestCafe 中,无论是 fixture
还是 it
, 都可以正向的选择或者反向的排除,使用 only
和 skip
:
fixture.only('添加到运行集');
fixture.skip('排除');
test.only('添加到运行集', t => {});
test.skip('排除', t => {});
延伸阅读
本文介绍了 TestCafe 的代码基本结构,本站还有 其他文章 深入介绍 TestCafe 的具体用法
如果您对本文有疑问或者寻求合作,欢迎 联系邮箱 。邮箱已到剪贴板
精彩评论
本站 是个人网站,采用 署名协议 CC-BY-NC 授权。
欢迎转载,请保留原文链接 https://www.lfhacks.com/tech/testcafe-code-structure/ ,且不得用于商业用途。