这篇文章将列出 JavaScript 测试方面最重要的工具,它融合了很多来自其他优秀文章的信息,并增加了我们多年来为不同产品实施不同测试解决方案的经验总结。
地址:https://github.com/jsdom/jsdom
jsdom 是 WHATWG DOM 和 HTML 标准的 JavaScript 实现,只使用普通的 JS 来模拟浏览器环境。
在这个模拟的浏览器环境中,可以非常快速地运行测试。jsdom 的缺点是不能在真实的浏览器之外模拟所有东西(例如不能截取屏幕截图),所以它会限制你的测试范围。
值得一提的是,JS 社区正在对它做出改进,当前版本非常接近真实的浏览器。
地址:https://istanbul.js.org/
Istanbul 将告诉你单元测试涵盖到了多少代码。它将以百分比的形式告诉你语句、代码行、函数和分支的覆盖率,你可以更好地了解还剩下哪些东西没有被覆盖到。
地址:
https://karma-runner.github.io/2.0/index.html
Karma 允许你在浏览器和浏览器模拟环境(如 jsdom)中运行测试。
Karma 提供了一个带有特殊页面的测试服务器,以便在页面环境中运行测试。这个页面可以在很多浏览器上运行。
这也意味着也可以使用 BrowserStack(https://www.browserstack.com/)之类的服务来远程运行测试。
地址:https://github.com/chaijs/chai
Chai 是最受欢迎的断言库。
地址:
https://github.com/unexpectedjs/unexpected
Unexpected 是一个断言库,语法与 Chai 略有不同。它也是可扩展的,因此基于它的库的断言会更加高级,例如 unexpected-react(https://github.com/bruderstein/unexpected-react)。
地址:http://sinonjs.org/
Sinon 是一个非常强大的独立测试工具,用于创建 stub 和 mock,适用于任何 JavaScript 单元测试框架。
地址:
https://github.com/testdouble/testdouble.js
testdouble 是一个相对没有那么流行的库,可以完成 Sinon 所做的事情,并声称可以做得更好。它在设计、理念和功能方面存在一些差异,在很多情况下,这些差异会很有用。
地址:https://wallabyjs.com/
Wallaby 是另一个值得一提的工具。它不是免费的,但很多用户会建议购买它。它可以在你的 IDE 中运行(它支持所有主要的 IDE),会在你写代码时运行测试,实时地告知你是否出现了错误。
地址:
https://github.com/cucumber/cucumber-js
Cucumber 可用于编写 BDD(行为驱动开发)测试用例,测试用例分为基于 Gherkin 语法的接受标准文件和与之对应的测试。
测试可以用框架支持的各种语言编写,包括 JS:
Feature: A reader can share an article to social networks
As a reader
I want to share articles
So that I can notify my friends about an article I liked
Scenario: An article was opened
Given I'm inside an article
When I share the article
Then the article should change to a "shared" state
module.exports = function() {
this.Given(/^I'm inside an article$/, function(callback) {
// functional testing tool code
})
this.When(/^I share the article$/, function(callback) {
// functional testing tool code
})
this.Then(/^the article should change to a "shared" state$/, function(callback) {
// functional testing tool code
})
}
很多团队发现这种语法比 TDD 更方便。
地址:https://github.com/mochajs/mocha
Mocha 是目前使用最多的库。与 Jasmine 不同,它需要与第三方断言、mock 和 spy 工具(通常是 Enzyme 和 Chai)一起使用。
因此 Mocha 用起来有点麻烦,也难以分成更多的库,但它更灵活、更容易扩展。
例如,如果你需要特殊的断言逻辑,可以 fork 一个 Chai,并使用自己的断言库替换 Chai 中的断言库。在 Jasmine 中也可以这么做,但在 Mocka 中,这种变化会更加明显。
社区——有很多插件和扩展用于测试独特的用例。
可扩展性——很多插件、扩展和库,如 Sinon,它包含了 Jasmine 所没有的功能。
全局对象——默认情况下创建测试结构全局对象,但显然不是 Jasmine 中的断言、spy 和 mock。
地址:https://facebook.github.io/jest/
Jest 是 Facebook 推荐的测试框架。它是基于 Jasmine 的,我们稍后会介绍 Jasmine。截至目前,Facebook 替换了 Jest 的大部分功能,并在其上添加了很多新功能。
Jest 的速度和便利性给人们留下了印象深刻。
性能——首先,Jest 实现了并行测试机制,被用在具有很多测试文件的大型项目上时速度更快。
UI——既清晰又方便。
随时可用——提供了断言、spy、mock,可以完成 Sinon 能够完成的所有事情。
全局对象——就像 Jasmine 一样,它默认创建测试全局对象。不过这也有不好的一面,因为它会降低测试的灵活性和可控性,但在大多数情况下,它会让你的工作变得更轻松:
快照测试——jest-snapshot(https://github.com/facebook/jest/tree/master/packages/jest-snapshot)由 Facebook 开发和维护,可以被用在任何其他框架中,作为框架集成工具或插件的一部分。
改进的模块模拟——Jest 提供了一种模拟大型模块的简便方法,用以提高测试速度。例如,可以模拟服务来解析 promise,而不是真的发出网络请求。
代码覆盖——内置了一个基于 Istanbul 的代码覆盖率工具。
可靠性——虽然这是一个相对年轻的库,但经过一两年的沉淀,现在基本稳定,目前所有主要的 IDE 和工具都支持它。
开发—— jest 只更新发生变更的文件,因此在 watch 模式下的运行速度非常快。
地址:https://github.com/jasmine/jasmine
Jest 就是基于 Jasmine 构建的。为什么需要使用 Jasmine?它已经存在了很长时间,社区写了很多有关它的文章,开发了很多与它有关的工具。
此外,Angular 仍然建议使用 Jasmine,而不是 Jest,尽管 Jest 也非常适合运行 Angular 测试,很多人也都这么做了。
随时可用——提供了测试所需的一切。
全局变量——提供了全局作用域内所有重要的测试功能。
社区——它从 2009 年就出现在市场上,现在有大量围绕它的文章、最佳实践和工具。
Angular——Angular 官方文档中建议使用 Jasmine。
地址:https://github.com/avajs/ava
Ava 是一个简单的测试库,可以并行运行测试。
随时可用——提供了测试所需的一切。
全局对象——它不会创建任何测试全局对象,因此你可以更好地控制测试的运行。
简单——简单的结构和断言,无需复杂的 API,同时支持很多高级特性。
开发—— Ava 只更新发生变更的文件,在 watch 模式下可以加快运行速度。
速度——作为单独的 Node.js 进程并行运行测试。
快照测试——作为框架的一部分。
地址:https://github.com/substack/tape
Tape 是这些框架中最简单的一个,它只是一个使用 Node 运行的 JS 文件,提供了“切中要害”的 API。
简单——没有复杂的 API,只有简约的结构和断言。
全局对象——不创建任何测试全局对象,因此你可以更好地控制测试运行。
测试之间不共享状态——Tape 不鼓励使用“beforeEach”之类的功能来确保测试的模块化以及最大限度地控制测试周期。
不需要 CLI——Tape 可以在任何可以运行 JS 的地方运行。
地址:
https://github.com/SeleniumHQ/selenium
Selenium 通过自动化浏览器来模拟用户行为。它不是专门针对测试而开发的,我们可以用它来实现多种用途。
我们可以通过多种方式、使用各种编程语言来控制 Selenium,某些工具甚至不需要写代码。
在 JavaScript 测试方面,通过 Selenium WebDriver(http://seleniumhq.github.io/selenium/docs/api/javascript/index.html)来控制 Selenium 服务器,将其作为 NodeJS 和操作浏览器的服务器之间的通信层。
Node.js <=> WebDriver <=> Selenium Server <=> FF/Chrome/IE/Safari
WebDriver 可以被导入到测试框架中,然后编写测试代码:
describe('login form', () => {
before(() => {
return driver.navigate().to('http://path.to.test.app/')
})
it('autocompletes the name field', () => {
driver
.findElement(By.css('.autocomplete'))
.sendKeys('John')
driver.wait(until.elementLocated(By.css('.suggestion')))
driver.findElement(By.css('.suggestion')).click()
return driver
.findElement(By.css('.autocomplete'))
.getAttribute('value')
.then(inputValue => {
expect(inputValue).to.equal('John Doe')
})
})
after(() => {
return driver.quit()
})
})
地址:https://github.com/appium/appium
Apium 提供了类似于 Selenium 的 API,可以使用以下工具在移动设备上测试网站:
iOS 9.3+,Apple 的 XCUITest:
https://developer.apple.com/reference/xctest
在 iOS 9.3 之前,Apple 的 UIAutomation:
https://developer.apple.com/library/ios/documentation/DeveloperTools/Reference/UIAutomationRef/
Android 4.2+,谷歌的 UiAutomator/UiAutomator2:
http://developer.android.com/tools/help/uiautomator/index.html
Android 2.3+,谷歌的 Instrumentation:
http://developer.android.com/reference/android/app/Instrumentation.html
Windows Phone,微软的 WinAppDriver:
http://github.com/microsoft/winappdriver
如果你在使用 Selenium 或基于 Selenium 的工具,你也可以使用 Apium 在移动设备上测试网站。
地址:https://github.com/angular/protractor
Protractor 对 Selenium 的库进行了包装,为 Angular 添加了一个改进的语法和特殊的 hook。
Angular——提供了特殊的 hook,当然也可以与其他 JS 框架一起使用。Angular 官方文档建议使用这个工具。
错误报告——良好的机制。
支持——支持 TypeScript,该库由 Angular 团队负责运营和维护。
地址:http://webdriver.io/
WebdriverIO 提供了自己的 selenium WebDriver 实现。
语法——非常简单易读。
灵活性——一个简单可将扩展的库。
社区——它得到了开发者社区的热情支持,社区提供了大量的插件和扩展。
地址:http://nightwatchjs.org/
Nightwatch 也提供了自己的 Selenium WebDriver 实现,以及自己的测试框架,包括测试服务器、断言和工具。
框架——可以与其他框架一起使用,而且如果你希望单独运行功能测试,它可能会特别有用。
语法——看起来最简单,最易读。
支持——不支持 TypeScript,这个库似乎比其他库获得支持稍微少一些。
地址:https://devexpress.github.io/testcafe/
TestCafe 是基于 Selenium 的工具之外的另一个绝佳选择。它在 2016 年底经过重写并开源。
它还有一个付费版本,提供了不需要编程的测试工具,比如测试记录器和客户支持。这点很重要,因为很多过时的文章错误地认为它是闭源的,并将其视为它的一个不足。
它将自己作为 JavaScript 脚本注入到网页中,而不像 Selenium 那样控制浏览器本身。因此,TestCafe 可以运行在任何浏览器中,包括移动设备,并且可以完全控制 JavaScript 的执行周期。
TestCafe 现在正处于大规模发展阶段,尽管它已经很稳定,并且功能也是齐全的。
快速设置——你只需要打开任何一个浏览器就运行测试。
跨浏览器和设备——支持很多浏览器和设备,可以与 SauceLabs 或 BrowserStack 一起使用,并在 Headless Chrome 和 Headless Firefox 中运行测试。
并行测试——TestCafe 可以同时在多个浏览器实例上运行测试,这可以显著缩短测试时间。
方便的错误报告。
自己的生态系统——TestCafe 使用自己的测试结构。它可能非常方便,因为 UI 测试通常与其他测试分开运行。
import { Selector } from 'testcafe';
fixture `Getting Started`
.page `https://devexpress.github.io/testcafe/example`
// Own testing structure
test('My first test', async t => {
await t
.typeText('#developer-name', 'John Smith')
.click('#submit-button')
.expect(Selector('#article-header').innerText)
.eql('Thank you, John Smith!')
})
地址:https://www.cypress.io/
Cypress 是 TestCafe 的直接竞争对手。它们做的事情比较相似,即将测试注入到网页中,提供更现代、更灵活和方便的测试方式。
Cypress 刚从内部测试转到公开测试(在 2017 年 10 月份),不过它们已经有很多采用者。
没有跨浏览器支持——现在只支持 Chrome(而且不是 headless 模式)。
缺乏高级功能——与 TestCafe 相比,仍然缺失平行测试和其他一些测试工具,但开发团队的产品路线图中包含了更多功能。
文档——翔实而清晰。
调试工具——容易调试和日志记录。
使用 Mocha 作为它的测试结构,这样你的 UI 测试与其他测试使用的是相同的结构,看起来更“标准”。
describe('My First Cypress Test', function() {
it("Gets, types and asserts", function() {
cy.visit('https://example.cypress.io')
cy.contains('type').click()
// Should be on a new URL which includes '/commands/actions'
cy.url().should('include', '/commands/actions')
// Get an input, type into it and verify that the value has been updated
cy.get('.action-email')
.type('fake@email.com')
.should('have.value', 'fake@email.com')
})
})
地址:
https://github.com/GoogleChrome/puppeteer
Puppeteer 是一个由谷歌开发的 Node.js 库。它提供了一组方便的 Node.js API 来控制 Headless Chrome。
Headless Chrome 其实也就是 Chrome v59+,可以通过 --headless 标记启动。当 Chrome 以 headless 模式运行时,它会公开一组 API,用来控制它自己,而 Puppeteer 是谷歌提供的用于控制 Chrome Headless 的 JavaScript 工具。
值得一提的是,Firefox 也在 2017 年底发布了 headless 模式。
请注意,其他一些测试工具也可以用来控制 Headless Chrome 和 Headless Firefox。例如:TestCafe、Karma。
Puppeteer 相对较新,但它已经有一个庞大的支持社区。
由于它是原生的,所以速度更快,并使用了最新的 Chrome 引擎,不像 PhantomJS 是基于 WebKit 的旧分支构建的。
Headless Chrome(Puppeteer 也是)的一个主要缺点是不支持 Flash 这样的扩展,在未来可能也不会支持。
地址:http://phantomjs.org/
Phantom 实现了 chromium 引擎,用来创建可控的类似 Chrome 的 headless 浏览器。
在谷歌发布 Puppeteer 之后,Phantom 的创建者和维护者 Vitaliy Slobodin 离开了这个项目,因此自 2017 年中期以来它的维护和开发速度要慢得多,尽管仍然有在维护。
那么,为什么你会使用 Phantom 而不是 Puppeteer ?
首先,因为它更加成熟,有很多很好的指南和工具。
它也被 CasperJS 等很多有用的工具所使用。
它使用较旧的 WebKit,因此可以模拟较旧的 Chrome 浏览器。
此外,Phantom 支持 Flash 等扩展。
地址:https://github.com/segmentio/nightmare
Nightmare 是一个很棒的 UI 测试库,它提供了一个非常简单的测试语法。
Nightmare 使用了与 Phantom 类似的 Electron,但 Electron 使用了更新的 Chromium,维护更加积极,因为 Electron 的主要目的是使用 JavaScript、HTML 和 CSS 构建跨平台的桌面应用程序。
下面是 Nightmare 代码与 Phantom 代码的区别。
yield Nightmare()
.goto('http://yahoo.com')
.type('input[title="Search"]', 'github nightmare')
.click('.searchsubmit')
地址:https://github.com/casperjs/casperjs
Casper 是在 PhantomJS 和 SlimerJS(与 Phantom 类似,只是使用了 Firefox 的 Gecko)基础上开发的,提供了导航、脚本和测试实用程序,并在创建 Phantom 和 Slimer 脚本时抽象出了很多复杂的异步内容。
Slimer 已经被广泛使用了很长一段时间,虽然被认为是实验性的,但在 2017 年底发布了测试版 1.0.0-beta.1,使用了新的 Headless Firefox,目前正在努力使版本稳定并发布 1.0.0。
Casper 可能会在不久的将来(2.0 版本中)从 PhantomJS 迁移到 Puppeteer,并成为测试 Headless Chrome 和 Headless Firefox 的绝佳工具。
地址:
https://github.com/codeception/codeceptjs/
与 CucumberJS 一样,Codecept 对不同库的 API 进行了另一种抽象,让你可以在测试时更多地专注于用户行为。
它看起来是这样的:
Scenario('login with generated password', async (I) => {
I.fillField('email', 'miles@davis.com');
I.click('Generate Password');
const password = await I.grabTextFrom('#password');
I.click('Login');
I.fillField('email', 'miles@davis.com');
I.fillField('password', password);
I.click('Log in!');
I.see('Hello, Miles');
});
你可以使用这段代码执行这些库(之前都介绍过):WebDriverIO、Protractor、Nightmare、Appium、Puppeteer。
如果你认为这种语法更符合你的需求,可以尝试一下。
英文原文:
https://medium.com/welldone-software/an-overview-of-javascript-testing-in-2018-f68950900bc3
2019 年 5 月 6-8 日,QCon 与您相约北京国际会议中心,深度解析业界前沿领域及技术趋势。点击 「 阅读原文 」或识别二维码了解 QCon 十周年精心策划,现在购票即享 8 折限时折扣,立减 1760 元,团购还有更多优惠!有任何问题欢迎联系票务小姐姐 Ring:电话 010-53935761,微信 qcon-0410