前端测试工具 TestCafe 测试代码结构

发表时间 ·

TestCafe 本身作为一款测试框架,有其自身特定的代码结构,本文介绍 TestCafe 的测试代码结构,并且与其他测试框架做一对比。

Mocha 的测试代码结构

首先来看较常见的 mochajs 的基本代码结构,如下:

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 的含义

fixture的中文含义是“夹具”,类似台钳:

在测试中(不仅仅是软件测试),fixture 的作用是设置被测物(DUT)的运行环境、将被测物的指标、状态调节到规定的状态。设置fixture的好处,第一是可重复,方便连续重复测试多个物件,第二是方便参数化,可以在多种参数环境下反复测试。

举个例子:考试的考场布置,就是一种 fixture,将教室中无关物品清除、设置好规定的桌椅器材,便于被测物(考生)顺利的经过测试。在下一场考试开始前,考场一定会被恢复到同样的状态。

汽车生产线中,整车下线前的最后一步,汽车将通过道路模拟机,测试转动、振动等指标,而且可以调整多种参数,以模拟各种道路情况。

从另一个角度理解 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 side 和 Client side

我们在 上文中提到过 ,TestCafe的特点在于新增了一个URL代理,在测试脚本和页面中起到中介作用,所以产生了服务侧(Server side) 和 客户端侧(Client side)的概念,如下图:

URL代理就是服务侧,编写的测试代码都是运行在服务侧。提供服务端的好处是,可以将测试代码与测试浏览器分离,运行在不同的主机上,比如 这篇文章 里提到的远程浏览器,访问服务端,一样能执行自动测试。

TestCafe 中的 Test Controller

Test Controller 可以看做是一个代理人,所有页面动作(比如寻找元素、输入文字、等待页面变化、校验数据)都由它集中执行。 服务侧 代码中,页面动作都封装为 Test Controller 的执行方法,而不再是零散的页面动作。

与之相比,普通UI自动化中的页面操作都是零散的单条语句执行。

观察 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"));

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 , 都可以正向的选择或者反向的排除,使用 onlyskip

fixture.only('添加到运行集');
fixture.skip('排除');

test.only('添加到运行集', t => {});
test.skip('排除', t => {});

相关文章   欢迎到 留言板 写下你的看法。
  本页面内容采用 署名协议 CC-BY 授权。欢迎转载,请保留原文链接