Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[译] 快速,完整的 Mocha 测试指南 #7

Open
collinxz-coder opened this issue Oct 14, 2019 · 0 comments
Open

[译] 快速,完整的 Mocha 测试指南 #7

collinxz-coder opened this issue Oct 14, 2019 · 0 comments

Comments

@collinxz-coder
Copy link
Owner

了解如何使用 Mocha 为 JavaScript 应用程序编写和运行测试

每个软件开发人员都应该学习构建可预测、不易出错且更具有弹性的软件。测试驱动开发(TDD)是可以实现这一目标的主要方法之一。简单的说,测试驱动的开发通常需要:

  1. 为所需要的功能编写测试
  2. 运行测试
  3. 实现软件功能
  4. 修复 bug 并重构直到所有测试通过
  5. 重复该周期以获取新功能

与其它编程语言一样,JavaScript 具有多种工具和框架,这些工具和框架可以在 Node.js 以及浏览器中进行测试驱动开发,例如:Jest, Jasmine, Mocha, QUnit, Karma, Cypress 等。

在本文中,您将快速而全面的了解如何使用 Mocha 来测试用 JavaScript 编写的软件功能。您将学习如何编写自己的测试套件以及如何使用 Mocha 运行测试。

Mocha 入门

Mocha 是一个 JavaScript 测试运行程序,它可以在 Node.js 和浏览器中运行。它提供了通过非常简单且相似的接口测试同步代码和异步代码的功能。在继续之前,您需要在本地计算机上全局安装 Mocha,或者作为项目的依赖项安装 Mocha。这里是使用 Node 包管理器(NPM)安装的方法:

全局安装:

npm i --global mocha

作为开发依赖安装到项目中:

npm i --save-dev mocha

在本地计算机上全局安装 mocha 可以使 mocha CLI 二进制可在命令行终端中使用。因此,您可以使用 Mocha 在终端上运行测试,如下所示:

mocha

但是,如果仅将 Mocha 安装为项目的开发依赖项,则可以从项目的 node_modules 目录访问 mocha 二进制文件,如下所示:

./node_modules/mocha/bin/mocha

要完成 Mocha 设置,您必须编写具有非常简单功能的单元测试,并配置脚本以使用 Mocha 运行测试。

Mocha 会自动在项目的 test 目录中查找测试。因此,你必须先在项目根目录中创建这个目录。

mkdir test

接下来,修改 package.json 文件中的 test 脚本来使用 Mocha 运行测试,它应该是这样的:

/* package.json */
{
    "scripts": {
        "test": "mocha"
    }
}

通过此设置,你可以非常简单的使用下面的命令在项目中运行测试:

npm test

编写测试

到现在为止,您已经通过 Mocha 运行测试做好了一切准备,但还没有任何测试可以运行。下一步将是编写针对软件所需功能的测试。

断言库

编写测试通常需要使用断言库。Mocha 不会区分您选择使用的任何断言库。如果您在 Node.js 环境中使用 Mocha,你可以使用内置的 assert 模块作为您的断言库。但是,您可以使用更广泛的断言库,例如 Chai, Expect.js, Should.js

对于本指南中所有测试,将使用 Chai 作为断言库。继续安装 Chai 作为您项目的依赖项,如下所示:

npm i --save-dev chai

Chai 提供如下断言样式:

  1. Assert 样式
var assert = require('chai').assert;
var numbers = [1, 2, 3, 4, 5];

assert.isArray(numbers, 'is array of numbers');
assert.include(numbers, 2, 'array contains 2');
assert.lengthOf(numbers, 5, 'array contains 5 numbers');
  1. Expect 样式
var expect = require('chai').expect;
var numbers = [1, 2, 3, 4, 5];

expect(numbers).to.be.an('array').that.includes(2);
expect(numbers).to.have.lengthOf(5);
  1. Should 样式
var should = require('chai').should();
var numbers = [1, 2, 3, 4, 5];

numbers.should.be.an('array').that.includes(2);
numbers.should.have.lengthOf(5);

您可以从本文档中了解有关 Chai 提供的断言和断言样式的更多信息。

Mocha 接口

Mocha 提供了多种接口来定义测试套件,hooks 和单个测试,即:BDD, TDD, Exports, QUnitRequire

在本文中,将使用 BDD 风格来定义和编写测试,你可以在本文档中检查可用的 Mocha 样式接口之间的比较。

使用 BDD 接口定义的测试套件如下所示:

// 开始一个或多个测试套件
describe('#sum()', function() {
    // 添加一个测试 hook
    beforeEach(function() {
        // ... 每次测试前执行的一些逻辑
    })

    // 测试功能
    it('should add numbers', function() {
        // 添加一个断言
        expect(sum(1, 2, 3, 4, 5)).to.equal(15);
    })

    // ... 更多测试
})

编写你的第一个测试套件

是时候使用 Mocha 编写并运行您的第一个测试套件了。下面是要实现的软件需求。

一个具有以下行为的 sum() 函数:

  1. 可以接收任意数量的参数
  2. 要求所有参数均为数字,如果不是数字则抛出错误
  3. 假设所有参数均为数字,则计算并返回所有参数的总和
  4. 如果未传递参数,则返回 0

根据最佳实践,首先使用所需功能的测试定义测试套件。

在 test 目录中添加一个 sum.js 并将下面代码片段添加到该文件中:

/* test/sum.js */

var sum = require('../sum');
var expect = require('chai').expect;

describe('#sum', function () {
    context('whitout arguments', function () {
        it('should return 0', function () {
            expect(sum()).to.equal(0);
        })
    })

    context('with number arguments', function () {
        it('should return sum of arguments', function () {
            expect(sum(1, 2, 3, 4, 5)).to.equal(15);
        })

        it('should return argument when only one argument is passed', function() {
            expect(sum(5)).to.equal(5);
        })
    })

    context('with non-number arguments', function() {
        it('should throw error', function() {
            expect(function() {
                sum(1, 2, '3', [4], 5)
            }).to.throw(TypeError, 'sum() expects only numbers.');
        })
    })
})

请注意,尽管尚未创建 sum 模块,但测试文件中仍需要该模块。还需要注意,sum() 调用包装在函数中,以测试传递非数字参数时是否引发错误。这是 Chai 断言库中对 .throw() 断言的要求。

接下来,实现 sum() 函数的功能,运行测试以确保所有测试都通过。

在项目的根目录中创建 sum.js 文件,并包含下面代码:

module.exports = function () {
    // 将参数对象转换成数组
    var args = Array.prototype.slice.call(arguments);

    // 如果参数数组中包含非数字参数,抛出 TypeError 错误
    if (!args.every(Number.isFinite)) {
        throw new TypeError('sum() expects only numbers.');
    }

    // 返回所有参数的和
    return args.reduce(function (a, b) {
        return a + b;
    }, 0);
}

您现在可以通过前面定义的 test 脚本在终端中运行测试:

npm test

你可以得到如下所示的输出:

测试异步代码

到目前为止,您编写的测试都是针对同步代码的。然而,大多数 Node.js 应用程序需要大量的异步代码。Mocha 还可以使用非常相似的代码轻松测试异步代码。以下任何一种代码都可用于通过 Mocha 测试异步代码:

  1. 使用回调方法
  2. 使用 Promise(用于支持 Promise 的环境)
  3. 使用 async / await(用于支持异步 function 的环境)

1. 使用回调方法

it() 函数的第二个参数中的函数支持一个可选的参数作为回调函数,如果传递了回调函数,Mocha 知道该测试是针对异步功能的。按照惯例,这个回调函数称为 done,但您可以自由使用任何标识符。

it('test expectation', function(done) {
    // 测试异步代码
    // 调用 done() 终止测试并继续下一个测试
})

关于 done 回调,需要注意以下几点:

  1. 必须调用 done() 回调以使 Mocha 终止测试并继续进行下一个测试,否则测试将一直运行直到超时。
  2. it() 中,done() 不能被多次调用。多次调用将引发错误。
  3. done() 回调是 Node 样式的回调,因此可以将 Error 实例(err) 作为其第一个参数。
  4. 使用 Error 实例调用 done() 回调将导致测试失败,并显示给定错误。

在继续之前,这是一个简单的模块,这个模块导出一个异步 md5() 函数以计算字符串的 MD5 值。

在项目根目录中添加一个新文件名为 md5.js,并添加以下代码:

module.exports = function (string, callback) {
    var withCallback = typeof callback === 'function';

    try {
        var hash = crypto.createHash('md5')
            .update(string)
            .digest('hex');

        withCallback && callback(null, hash);
    } catch (e) {
        if (withCallback) {
            callback(e);
        } else {
            throw e;
        }
    }
}

以下代码片段使用回调函数对异步函数进行了简单测试。

在项目的 test 目录中创建一个新的 md5.js 文件,并向其中添加以下内容:

/* test/md5.js */

var md5 = require('../md5');
var expect = require('chai').expect;

describe('#md5()', function() {
    context('with string argument', function() {
        it('should compute MD5 hash', function(done) {
            md5('Glad Chinda', function(err, hash) {
                // 使用 error 来调用 done() 回调函数,
                // 来终止带有错误的测试
                if (err) return done(err);

                // 添加以下断言
                expect(hash)
                    .to.be.a('string')
                    .that.matches(/^[a-f0-9]{32}$/)
                    .and.equal('877dbb93f50eb8a89012e15bd37ee7e4');
                
                // 调用 done() 回调函数来终止测试
                done();
            })
        })
    })

    context('with non-string argument', function() {
        it('should throw an error', function(done) {
            md5(12345, function(err, hash) {
                // 使用错误调用 done() 回调来终止测试
                if (err) {
                    expect(function() { throw err })
                        .to.throw(TypeError, 'The "data" argument must be one of type string, TypedArray, or DataView. Received type number');
                    
                    // 最后调用 done() 回调来终止测试并返回
                    return done();
                }

                // 调用 done() 回调来终止测试
                done();
            })
        })
    })
})

如果你在终端中运行测试,可以得到类似于以下内容的输出:

2. 使用 Promise

如果您在支持 Promise 的环境中进行开发,则大多数异步操作可能会基于 Promise。Mocha 还使您可以测试使用 Promise 的异步代码。

每当您从传递给 it() 的函数中返回一个 Promise 时,Mocha 就会知道要测试的功能时异步的,因此它会在继续下一个测试之前等待实现 Promise。

从 Mocha V3.0.0 以及更高版本开始,在返回 promise 时调用 done() 回调将导致异常,因此不允许这样做。但是在旧版本的 Mocha 中,该调用将被忽略。

为了测试使用 promise 的异步代码,您将创建基于 Promise 的 md5 的另一个版本。

在项目根目录中创建一个新的文件 promise-md5.js 并添加下面代码:

/* promise-md5.js */
const md5 = require('./md5');

module.exports = (string) => new Promise(
    (resolve, reject) => {
        md5(string, (err, hash) => {
            return err ? reject(err) : resolve(hash);
        })
    }
)

以下代码段包含一个用于 promise-md5 模块的简单测试套件。在 test 目录中创建一个 promise-md5.js 文件并添加以下内容:

/* test/promise-md5.js */

var promiseMd5 = require('../promise-md5');
var expect = require('chai').expect;

describe('#promiseMd5()', function () {
    context('with string argument', function () {
        it('should compute MD5 hash', function () {
            return promiseMd5('Glad Chinda')
                .then(function (hash) {
                    // 添加一些断言
                    expect(hash)
                        .to.be.a('string')
                        .that.matches(/^[a-f0-9]{32}$/)
                        .and.equal('877dbb93f50eb8a89012e15bd37ee7e4');
                })
        })
    })

    context('with non-string argument', function () {
        it('should throw an error', function () {
            return promiseMd5(12345)
                .catch(function (err) {
                    expect(function () { throw err })
                        .to.throw(TypeError, 'The "data" argument must be one of type string, TypedArray, or DataView. Received type number');
                })
        })
    })
})

现在,继续使用此稍微修改的测试命令运行测试:

npm test -- -f promiseMd5

此命令使用 -- 将命令选项和参数传递到基础的 Mocha CLI 二进制文件。-f 标志指示 mocha 仅运行包含给定字符串的测试,在这种情况下,该测试为 promiseMd5。

输出如下所示:

3. 使用 async / await

对于支持最新 async / await 语法的环境,Mocha 还支持将异步函数作为第二个参数传递给 it()。因此,以前的 promise-md5.js 测试可以重写如下:

/* test/promise-md5.js */

var promiseMd5 = require('../promise-md5');
var expect = require('chai').expect;

describe('#promiseMd5()', function () {
    context('with string argument', function () {
        it('should compute MD5 hash', async function () {
            // 使用 await 等到 Promise 实现
            var hash = await promiseMd5('Glad Chinda');

            // 添加一些断言
            expect(hash)
                .to.be.a('string')
                .that.match(/^[a-z0-9]{32}$/)
                .and.equal('877dbb93f50eb8a89012e15bd37ee7e4');
        })
    })

    context('with non-string argument', function() {
        it('should throw an error', async function() {
            await promiseMd5(12345).catch(function(err) {
                // 添加一个断言以检查错误
                expect(function() { throw err })
                    .to.throw(TypeError, 'The "data" argument must be one of type string, TypedArray, or DataView. Received type number');
            })
        })
    })
})

利用测试 hooks

Mocha 提供了创建测试 hooks 的功能,hooks 基本上是配置为在测试之前或之后运行的逻辑。它们对于设置测试的前提条件或者在测试后清理资源很有用。使用默认的 BDD 接口,Mocha 提供了四个hooks:

  1. before() - 在块中的第一个测试用例之前运行一次
  2. beforeEach() - 在每个测试用例前运行
  3. afterEach() - 在每个测试用例之后运行
  4. after() - 在块中的最后一个测试用例之后运行一次

根据适用于给定测试套件的 hooks,hooks 将按确定的顺序与套件中的测试一起运行,如下所示:

before() -> beforeEach() -> test() -> afterEach() -> after()

创建 hooks

每个挂钩基本上都将回调参数作为参数。回调函数包含触发 hooks 时要执行的逻辑。就像常规测试用例一样,逻辑可以是同步的也可以说异步的。

describe('some module', function() {
    beforeEach(function() {
        // 每次测试之前运行的一些逻辑
        // 逻辑可以是同步的,也可以是异步的
    })
})

hooks 也可以将可选描述作为第一个参数,这使得跟踪错误更加容易。但是,如果将命名函数作为参数传递给 hooks,如果未传递显示描述,则将函数名用作描述。

describe('some module', function() {
    // 使用命名函数
    beforeEach(function createSession() {
        // beforeEach: createSession
    })

    // 使用描述
    beforeEach('create a user session', function() {
        // beforeEach: create a user session
    })
})

根套件

在 describe() 块外部定义 hooks 时,该钩子便成为根级 hooks。根 hooks 适用于所有测试文件,无论它们在何处定义。这是因为 Mocha 隐式创建了一个 describe() 块,称为根套件。

因此,在以下代码片段中,每个文件中的每个测试之后都会触发 afterEach() 挂钩。

var tests = 1;

// 在任何文件中的任何测试运行之后执行
afterEach(function() {
    console.log('Test #' + (tests++));
})

有时,您可能需要在运行任何测试套件之前执行异步操作。Mocha 允许您通过使用 --delay 选项运行 mocha 二进制文件来延迟根套件。对于您的项目的测试命令, 它将如下所示:

npm test -- --delay

运行此命令指示 Mocha 将特殊的 run() 回调函数附加到全局上下文。调用 run() 函数将指示 Mocha 运行已描述的所有测试套件。因此,可以在异步操作完成之后调用 run() 来运行测试。

例如,将以下代码片段添加到您先前创建的任何测试文件中(它永远不能在 it() 块内):

// 将测试延迟到 5 秒后
setTimeout(function () {
    run();
}, 5000);

现在使用下面的命令运行测试:

npm test -- --delay

请注意,测试延迟了 5 秒钟,然后运行。但是,如果不调用 run() 方法,则测试将永远不会运行。输出如下所示:

测试还不够 - 确保您的应用正常运行

LogRocket 是一个前端日志记录工具,可以让您像在您自己的浏览器中一样重播问题。无需猜测错误发生的原因,或询问用户屏幕截图和日志文件,LogRocket 使您可以重播会话以快速了解出了什么问题。

除了记录 Redux actions 和状态外,LogRocket 还记录控制台日志,JavaScript 错误,堆栈跟踪,带有请求头 + 正文、浏览器元数据和自定义网络日志的网络请求/响应。它还使用 DOM 来记录页面上的 HTML 和 CSS,甚至可以为最复杂的单页面应用程序重新创建像素完美的视频。

控制测试

每当未将回调函数作为第二个参数传递给 it() 时,测试用例就会标记为待处理(pending),这表明该测试尚未编写。待处理测试不是失败的测试,它们包含在测试结果中。

describe('#flattenArray()', function() {
    // 待处理测试
    it('should flatten array');
})

包括和排除测试

您还可以指定应该运行或不应该运行的测试套件和测试用例。Mocha 提供了两种有用的方法:only()skip(),用于控制测试套件和测试用例的排它和包含行为。

使用 describe.skip() 方法组织套件中的测试运行,并使用 describe.only() 方法确保套件中的测试运行。

// 此测试套件中的测试将运行
describe.only('#flattenArray()', function() {
    it('should flatten array', function() { })
})

// 此测试套件中的测试无法运行
describe('#mergeArray()', function() {
    it('should merge two arrays', function() { })
})

使用 it() 的测试用例也是如此。通过在传递给 it() 的回调函数中调用 this.skip() 可以在运行时跳过测试。这样就可以根据某些条件动态跳过测试。

调用 this.skip() 有效地终止测试。因此最好的做法是避免在调用 this.skip() 之后执行其它命令。使用 this.skip() 在运行时跳过的每个测试都将标记为待处理测试(pending)。

describe.only('#flattenrray()', function() {
    // 这个测试将被运行
    it.only('should flatten array', function() { });

    // 这个测试无法运行
    it('should recursively flatten array', function() { });
})

describe.only('#mergeArray()', function() {
    // 对于生产环境,将在运行时跳过此测试
    // 在生产中,它将无法运行,并将被标记为待处理
    it('should merge two arrays', function() {
        if (process.env.NODE_ENV === 'production') {
            return this.skip();
        }
    })
})

测试环境输出如下:

生产环境下,运行效果如下:

你可以多次使用 .only().skip() 选择一组要运行的套件和测试。但是,您必须注意以下几点:

  1. 嵌套套件仍将执行
  2. 如果过存在 hooks,仍将执行钩子
  3. 测试将优先

重试测试

Mocha 提供了一种功能,用于指定可以重试失败的测试的次数。不建议在单元测试中使用它,但是在编写端到端测试(由于某些原因可能无法使用某外部资源)时,此功能很有用。

Mocha 提供了 this.retries() 函数,该函数可以让您指定允许重试的次数。对于每次重试,Mocha 都会运行重新 beforeEach() 和 afterEach() hooks,但不会重新运行 before() 和 after() 钩子。

以下代码片段显示一个简单的示例,改示例使用 Cypress 测试运行器访问网页。如果服务器响应中的 status code 不是 2xx, 可能是因为网速慢或者网络连接不好,测试将被标记为失败。

describe('test medium site', function() {
    // 这个套件中所有失败的测试都会重试2次
    this.retries(2);

    it('should load medium homepage', function() {
        // 这个测试用例测试失败后,会被重复5次
        this.retries(5);

        cy.visit('https://medium.com');
    })
})

使用 this.retries(5),这个测试允许在失败后重试最多5次。

慢速的测试

Mocha 允许你指定一个时间长度,所有执行时间超过这个值的测试将被认为是慢速测试。可以使用 this.slow() 方法来达到这个目的。这个方法的参数是一个以毫秒为单位的数字。

describe('slow test', function() {
    // 在一秒之后,测试将被认为是缓慢的
    this.slow(1000);

    // 在指定的一秒钟之后完成
    it('should be complete in a second', function(done) {
        setTimeout(done, 1500);
    })

    // 立即完成
    it('should be complete instantly', function() { })
})

注意上图中用红色文字标记的(1506)表示测试的执行时间,这条测试被认为是慢速测试,因为它的执行时间超过了 this.slow(1000) 中定义的1秒才执行完成。

超时时间

默认情况下,Mocha 测试执行时间最多为2秒(2000毫秒)。所有超过这个时间的测试都被认为超时。当一个测试超时时,这个测试被标记为失败,并且会抛出 timeout 错误。

但是,Mocha 提供了 this.timeout() 方法,用于设置给定的测试套件,hooks或者测试用例的超时时间。这个方法接收一个以毫秒为单位 int 数值作为参数。

可以在不同的级别(测试套件, hooks 或测试用例)配置不同的超时时间:

describe('some time-consuming operation', function() {
    // 给这个测试用例设置 5 秒的超时时间
    this.timeout(5000);

    before('some long step', function(done) {
        // 设置 hooks 的超时时间
        this.timeout(2500);

        setTimeout(done, 2250);
    })

    it('should take less than 200ms', function(done) {
        // 为当前测试用例设置超时时间
        this.timeout(200);

        setTimeout(done, 150);
    })
})

如果像关闭超时限制,则在调用 this.timeout() 时传递 0 即可。

describe('some time-consuming operation', function() {
    // 在这个测试用例中关闭超时限制
    this.timeout(0);

    it('should take a long time', function(done) {
        setTimeout(done, 10000);
    })
})

Mocha CLI 选项

到目前为止,您已经了解了 Mocha 所提供的用于编写测试的所有工具。但是在使用 Mocha 时,仍然可以使用很多实用工具,并且只有在使用 Mocha CLI 时,才能使用的一些实用工具。

要获取 Mocha CLI 所提供的可用选项列表,请运行以下命令:

mocha -h

在你的项目中,你可以实用下面的命令来代替:

npm test -- -h

监听测试文件

-w, --watch 标志指示 Mocha 监听测试文件的变动并重新运行测试。这对于在开发过程中编写测试非常有用。

mocha --watch

Async 和 bail

-A, --async-only 标志强制所有测试必须传递回调函数或返回一个 promise,从而异步执行。对于未指定回调函数或者未返回 promise 的测试将被标记为失败。

mocha --async-only

-b, --bail 标志指定只要有一个测试用例没有通过,就停止后面所有的测试用例。这对于持续继承很有用。

mocha --bail

处理超时和慢速测试

除了使用 this.timeout() 方法,还可以使用 -t, --timeout <ms> 来设置测试用例的超时时间。Mocha 的默认超时时间是2秒。你可以传递一个以毫秒为单位的数字来表示毫秒或者是带(s)后缀的数字表示秒。

mocha -t 3000

等价于:

mocha --timeout 3s

如果要禁用超时限制,可以使用 --no-timeouts,这等价于 --timeout 0:

mocha --no-timeouts

同样的,在 CLI 中也可以设置慢速测试的阈值,使用 -s, --slow <ms> 标志。默认的阈值是 75ms。如你所见,Mocha 使用此阈值高亮显示执行时间太长的测试。

mocha --slow 100

运行匹配的测试

Mocha 使用 -g, --grep <pattern> 标志来通过正则表达式匹配需要执行的测试和测试套件。

前面我们已经提到过,通过 -f, --fgrep <string> 标志可以匹配包含指定字符串的测试和测试套件。

例如:下面命令执行所有包含 array 字符串的测试和测试用例。

mocha -f array

导入文件和模块

-r, --require <module> 标志允许您导入在测试文件中使用的模块/库(例如断言库),而不是在代码中手动调用 require()。适用于诸如 should.js 之类的模块。但是要访问模块的导出(exports),您将必须在代码中 require 该模块。

mocha --require should

--file <file> 运行您添加一个或多个想要优先包含在测试套件中的文件。这些文件可能包含测试所需要的某些设置逻辑。--file 标志可以多次使用以包含多个文件。

Mocha 接口和报告

如前所示,Mocha 提供了多个用于编写测试的接口。默认使用的是 BDD 接口,这是本指南中一直使用的接口。-u, --ui <name> 允许您指定另外一个需要使用的接口。

mocha --ui exports

通过 -R, --reporter <name> 标志,您可以指定测试报告的格式。默认的是 spec格式。Mocha 还允许您使用此标志指定第三方报告格式。

mocha -R list

除了 spec,官网还给出了其它许多报告格式

浏览器中的 Mocha

Mocha 测试运行程序也可以在浏览器中使用。Mocha 的每一个发行版都包含 ./mocha.css./mocha.js 用于在浏览器中使用。这里是在浏览器上运行 Mocha 测试的简单步骤。

设置公共文件

在你的项目根目录中创建一个 public 目录。然后在 public 目录中创建一个名为 index.html 的文件,并添加下面的代码:

<!-- public/index.html -->

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>Mocha Tests</title>

    <!-- Include Mocha CSS styles -->
    <link href="https://cdn.rawgit.com/mochajs/mocha/2.2.5/mocha.css" rel="stylesheet">
</head>

<body>
    <div id="mocha"></div>

    <!-- Add the Chai assertion library -->
    <script src="http://chaijs.com/chai.js"></script>

    <!-- Add the Mocha test library -->
    <script src="https://cdn.rawgit.com/mochajs/mocha/2.2.5/mocha.js"></script>

    <script>
    // Set chai.expect as a global variable
    var expect = chai.expect;

    // Setup Mocha to use the BDD interface
    mocha.setup('bdd');
    </script>

    <!-- Import the sum function -->
    <script src="/sum.js"></script>

    <!-- Import the tests for the sum function -->
    <script src="/sum.test.js"></script>

    <script>
    // Run the tests with Mocha
    mocha.run();
    </script>
</body>
</html>

我们将 Mocha 和 Chai 断言库的静态 CSS 和 JS 文件导入到页面中。<div id="mocha"></div> 元素用于显示测试结果。

在设置 Chai 时,将 chai.expect 映射到名为 expect 的全局变量上,以便可以在测试脚本中使用它进行断言。

通过调用 mocha.setup('bdd') 来告知 Mocha 选用 BDD 接口。使用 mocha.run() 方法运行测试。

接下来继续在您之前创建的 public 目录中创建一个名为 sum.js 的新文件,并添加下面这些内容:

/* public/sum.js */

function sum() {
    // Convert argument object to array
    var args = Array.prototype.slice.call(arguments);

    // Throw error if arguments contain non-finite number values
    if (!args.every(Number.isFinite)) {
        throw new TypeError('sum() expects only numbers');
    }

    // Return the sum of the arguments
    return args.reduce(function(a, b) {
        return a + b;
    }, 0);
}

接下来继续创建 sum.test.js 文件,并添加下面内容:

/* public/sum.test.js */

describe('#sum()', function() {
    context('without arguments', function () {
        it('should return 0', function () {
            expect(sum()).to.equal(0);
        })
    })

    context('with number arguments', function () {
        it('should return sum of arguments', function () {
            expect(sum(1, 2, 3, 4, 5)).to.equal(15);
        })

        it('should return argument when only one argument is passed', function () {
            expect(sum(5)).to.equal(5);
        })
    })

    context('with non-number arguments', function () {
        it('should throw error', function() {
            expect(function() {
                sum(1, 2, '3', [4], 5)
            }).to.throw(TypeError, 'sum() expects only numbers.')
        })
    })
})

设置一个简单的服务器

接下来,可以选择为公共文件设置一个简单的服务器。在这个案例中,我们使用 live-server。继续按照以下步骤将其安装为项目依赖:

npm install --save-dev live-server

修改 pachage.json 文件的 scripts 部分,使其包含用于提供公共文件并在浏览器中运行 Mocha 测试的脚本。它看起来应该是这样:

/* package.json */
{
    "scripts": {
        "test": "mocha",
        "test:browser": "live-server --port=9000 --mount=/:public"
    }
}

我们在这里添加了一个 test:browser 脚本,已启动 9000 端口来访问 public 目录中的文件。

最后,我们在命令行中执行下面命令:

npm run test:browser

这应该在 9000 端口上启动服务器并为您启动浏览器选项卡来展示它。浏览器上的测试输出应该类似于下面图片:

总结

在本指南中,您已经学习了在 Node.js 和浏览器上 Mocha 测试的基础只是。您还学习了如何为 JavaScript 应用程序编写和运行测试。

尽管本指南内容广泛,但您始终可以参考 Mocha 文档以获取本指南未涵盖的各个方面。

原文地址

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant