使用Mocha和Assert测试Node.js 模块

 

2024软件测试面试刷题,这个小程序(永久刷题),靠它快速找到工作了!(刷题APP的天花板)-CSDN博客跳槽涨薪的朋友们有福了,今天给大家推荐一个软件测试面试的刷题小程序。https://blog.csdn.net/weixin_54696666/article/details/139783730?spm=1001.2014.3001.5501https://blog.csdn.net/weixin_54696666/article/details/139783730?spm=1001.2014.3001.5501icon-default.png?t=N7T8https://blog.csdn.net/weixin_54696666/article/details/139783730?spm=1001.2014.3001.5501

我们在 TODO 模块中想要的功能之一是 CSV 导出功能。这会将我们存储的所有 TODO 连同完成的状态打印到一个文件中。这要求我们使用该fs模块——一个用于处理文件系统的内置 Node.js 模块。

  写入文件是一种异步操作。在 Node.js 中有很多方法可以写入文件。我们可以使用回调、Promises 或async/await关键字。在本节中,我们将看看我们如何为这些不同的方法编写测试

  回调

  回调函数是用作异步函数的参数的函数。当异步操作完成时调用它。

  让我们在我们的Todos类中添加一个名为saveToFile(). 这个函数将通过遍历我们所有的 TODO 项并将该字符串写入文件来构建一个字符串。

  打开你的index.js文件:

nano index.js

  在此文件中,添加以下代码:

const fs = require('fs');

class Todos {

    constructor() {

        this.todos = [];

    }

    list() {

        return [...this.todos];

    }

   

    add(title) {

        let todo = {

            title: title,

            completed: false,

        }

        this.todos.push(todo);

    }

    complete(title) {

        if (this.todos.length === 0) {

            throw new Error("You have no TODOs stored. Why don't you add one first?");

        }

        let todoFound = false

        this.todos.forEach((todo) => {

            if (todo.title === title) {

                todo.completed = true;

                todoFound = true;

                return;

            }

        });

        if (!todoFound) {

            throw new Error(`No TODO was found with the title: "${title}"`);

        }

    }

    saveToFile(callback) {

        let fileContents = 'Title,Completed\n';

        this.todos.forEach((todo) => {

            fileContents += `${todo.title},${todo.completed}\n`

        });

        fs.writeFile('todos.csv', fileContents, callback);

    }

}

module.exports = Todos;

  我们首先必须在我们的文件中导入fs模块。然后我们添加了我们的新saveToFile()功能。我们的函数采用一个回调函数,一旦文件写入操作完成,就会使用该回调函数。在该函数中,我们创建一个fileContents变量来存储我们想要保存为文件的整个字符串。它使用 CSV 的标头初始化。forEach()然后我们使用内部数组的方法遍历每个 TODO 项。当我们迭代时,我们添加各个对象的title和属性。

  最后,我们使用fs模块来编写带有writeFile()函数的文件。我们的第一个参数是文件名:todos.csv. 第二个是文件的内容,在本例中是我们的fileContents变量。我们的最后一个参数是我们的回调函数,它处理任何文件写入错误。

  保存并退出文件。

  现在让我们为我们的saveToFile()函数编写一个测试。我们的测试将做两件事:首先确认文件存在,然后验证它的内容是否正确。

  打开index.test.js文件:

nano index.test.js

  让我们首先fs在文件顶部加载模块,因为我们将使用它来帮助测试我们的结果:

const Todos = require('./index');

const assert = require('assert').strict;

const fs = require('fs');

...

  现在,在文件末尾添加我们的新测试用例

...

describe("saveToFile()", function() {

    it("should save a single TODO", function(done) {

        let todos = new Todos();

        todos.add("save a CSV");

        todos.saveToFile((err) => {

            assert.strictEqual(fs.existsSync('todos.csv'), true);

            let expectedFileContents = "Title,Completed\nsave a CSV,false\n";

            let content = fs.readFileSync("todos.csv").toString();

            assert.strictEqual(content, expectedFileContents);

            done(err);

        });

    });

});

  像以前一样,我们习惯describe()将我们的测试与其他测试分开分组,因为它涉及新功能。该it()功能与我们的其他功能略有不同。通常,我们使用的回调函数没有参数。这一次,我们有done一个论据。当测试带有回调的函数时,我们需要这个参数。Mocha使用done()回调函数来告诉它异步函数何时完成。

  在 Mocha 中测试的所有回调函数都必须调用done()回调。如果没有,Mocha 永远不会知道函数何时完成,并且会一直等待信号。

  继续,我们创建我们的Todos实例并向其中添加一个项目。然后我们调用该saveToFile()函数,并带有一个捕获文件写入错误的回调。请注意我们对此函数的测试如何驻留在回调中。如果我们的测试代码在回调之外,只要在文件写入完成之前调用代码,它就会失败。

  在我们的回调函数中,我们首先检查我们的文件是否存在:

...

assert.strictEqual(fs.existsSync('todos.csv'), true);

...

  如果其参数中的文件路径存在,则该fs.existsSync()函数返回,否则返回。

  [note] 注意: 模块的fs函数默认是异步的。然而,对于关键功能,他们做了同步对应。通过使用同步函数,这个测试更简单,因为我们不必嵌套异步代码来确保它工作。在fs模块中,同步函数通常以"Sync"名称结尾。

  然后我们创建一个变量来存储我们的期望值:

...

let expectedFileContents = "Title,Completed\nsave a CSV,false\n";

  我们使用readFileSync()模块fs来同步读取文件:

let content = fs.readFileSync("todos.csv").toString();

...

  我们现在为readFileSync()文件提供正确的路径:todos.csv. 作为readFileSync()返回一个Buffer存储二进制数据的对象,我们使用它的toString()方法,以便我们可以将它的值与我们期望保存的字符串进行比较。

  和之前一样,我们使用assert模块的strictEqual做一个比较:

...

assert.strictEqual(content, expectedFileContents);

...

  我们通过调用回调来结束我们的测试done(),确保 Mocha 知道停止测试该案例:

...

done(err);

...

  我们提供err对象,done()以便 Mocha 在发生错误的情况下无法通过测试。

  保存并退出index.test.js。

  npm test让我们像以前一样运行这个测试。您的控制台将显示以下输出:

Output

...

integrated test

    ✓ should be able to add and complete TODOs

  complete()

    ✓ should fail if there are no TODOs

  saveToFile()

    ✓ should save a single TODO

  3 passing (15ms)

  您现在已经使用回调测试了第一个使用 Mocha 的异步函数。但是Promise 在Node.js代码中比回调更普遍,接下来,让我们学习如何使用 Mocha 来测试它们。

  Promise

  Promise是一个JavaScript 对象,它最终会返回一个值。当一个 Promise 成功时,它就被解决了。当它遇到错误时,它会被拒绝。

  让我们修改saveToFile()函数,使其使用 Promises 而不是回调。打开index.js:

nano index.js

  首先,我们需要更改fs模块的加载方式。在您的index.js文件中,将require()文件顶部的语句更改为如下所示:

...

const fs = require('fs').promises;

...

  我们刚刚导入了fs使用 Promises 而不是回调的模块。现在,我们需要进行一些更改,saveToFile()以便它可以与 Promises 一起使用。

  在您的文本编辑器中,对函数进行以下更改以saveToFile()删除回调:

...

saveToFile() {

    let fileContents = 'Title,Completed\n';

    this.todos.forEach((todo) => {

        fileContents += `${todo.title},${todo.completed}\n`

    });

    return fs.writeFile('todos.csv', fileContents);

}

...

  第一个区别是我们的函数不再接受任何参数。使用 Promises,我们不需要回调函数。第二个更改涉及文件的写入方式。我们现在返回writeFile()promise 的结果。

  保存并关闭index.js.

  现在让我们调整我们的测试,使其适用于 Promises。打开index.test.js:

nano index.test.js

  saveToFile()将测试更改为:

...

describe("saveToFile()", function() {

    it("should save a single TODO", function() {

        let todos = new Todos();

        todos.add("save a CSV");

        return todos.saveToFile().then(() => {

            assert.strictEqual(fs.existsSync('todos.csv'), true);

            let expectedFileContents = "Title,Completed\nsave a CSV,false\n";

            let content = fs.readFileSync("todos.csv").toString();

            assert.strictEqual(content, expectedFileContents);

        });

    });

});

  我们需要做的第一个改变是done()从它的参数中移除回调。如果 Mocha 传递done()参数,则需要调用它,否则会抛出如下错误:

1) saveToFile()

       should save a single TODO:

     Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/home/ubuntu/todos/index.test.js)

      at listOnTimeout (internal/timers.js:536:17)

      at processTimers (internal/timers.js:480:7)

  测试 Promises 时,不要done()在it().

  为了测试我们的Promises,我们需要将我们的代码放入then()函数中。请注意,我们在测试中返回了这个 Promise,并且我们没有一个函数可以在被拒绝catch()时捕获。

  我们返回承诺,以便函数中抛出的任何错误都会then()冒泡到it()函数中。如果错误没有冒泡,Mocha 不会使测试用例失败。测试 Promises 时,需要return在Promise被测试对象上使用。如果没有,您将面临误报的风险。

  我们也省略了该catch()子句,因为 Mocha 可以检测何时拒绝承诺。如果被拒绝,它会自动通过测试。

  现在我们已经完成了测试,保存并退出文件,然后运行 Mochanpm test并确认我们得到了成功的结果:

Output

...

integrated test

    ✓ should be able to add and complete TODOs

  complete()

    ✓ should fail if there are no TODOs

  saveToFile()

    ✓ should save a single TODO

  3 passing (18ms)

  我们已经更改了代码和测试以使用 Promises,现在我们确定它可以工作。但是最新的异步模式使用async/await关键字,因此我们不必创建多个then()函数来处理成功的结果。让我们看看如何使用async/进行测试await。

  async/await

  async/关键字使使用awaitPromises 变得不那么冗长。一旦我们使用关键字将函数定义为异步async,我们就可以使用关键字在该函数中获得任何未来的结果await。这样我们就可以使用 Promises 而不必使用then()orcatch()函数。

  我们可以使用/来简化saveToFile()基于 promise 的测试。在您的文本编辑器中,对测试进行以下小修改:async``await``saveToFile()``index.test.js

...

describe("saveToFile()", function() {

    it("should save a single TODO", async function() {

        let todos = new Todos();

        todos.add("save a CSV");

        await todos.saveToFile();

        assert.strictEqual(fs.existsSync('todos.csv'), true);

        let expectedFileContents = "Title,Completed\nsave a CSV,false\n";

        let content = fs.readFileSync("todos.csv").toString();

        assert.strictEqual(content, expectedFileContents);

    });

});

  第一个变化是函数使用的it()函数现在在async定义时具有关键字。这允许我们await在其正文中使用关键字。

  第二个变化是在我们调用时发现的saveToFile()。关键字在await调用之前使用。现在 Node.js 知道要等到该函数解决后再继续测试。

  现在我们将then()函数中的代码移到it()函数体中,我们的函数代码更易于阅读。运行此代码npm test会产生以下输出:

Output

...

integrated test

    ✓ should be able to add and complete TODOs

  complete()

    ✓ should fail if there are no TODOs

  saveToFile()

    ✓ should save a single TODO

  3 passing (30ms)

  我们现在可以适当地使用三种异步范式中的任何一种来测试异步函数。

  结论

  在本教程中,编写了一个 Node.js 模块来管理 TODO 项并使用 Node.js REPL 手动测试代码。然后,创建了一个测试文件并使用 Mocha 框架运行自动化测试。使用该assert模块,您可以验证您的代码是否有效。还使用 Mocha 测试了同步和异步函数。最后,使用 Mocha 创建了钩子,使编写多个相关的测试用例更具可读性和可维护性。

最后: 下方这份完整的软件测试视频教程已经整理上传完成,需要的朋友们可以自行领取【保证100%免费】

​​​软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

在这里插入图片描述

在这里插入图片描述

  • 7
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
单元测试是一种软件测试方法,用于测试代码的最小可测试单元。在Node.js中,可以使用Mocha和Chai等测试框架进行单元测试。下面是一个使用Mocha和Chai测试一个简单函数的例子: ```javascript // 引入断言库chai var assert = require('chai').assert; // 引入要测试的函数 var add = require('../add.js'); // 编写测试用例 describe('add', function() { it('should return 3 when the input is 1 and 2', function() { assert.equal(add(1, 2), 3); }); }); // add.js function add(a, b) { return a + b; } module.exports = add; ``` 在上面的例子中,我们首先引入了Chai的断言库,然后引入了要测试的函数add。接着,我们使用describe函数定义了一个测试套件,使用it函数定义了一个测试用例。在测试用例中,我们使用assert.equal函数断言add(1, 2)的返回值应该等于3。最后,我们将add函数导出,以便在测试文件中引入。 除了使用Mocha和Chai,还可以使用SuperTest对HTTP接口进行测试。SuperTest是一个基于SuperAgent的库,可以方便地模拟HTTP请求和响应。下面是一个使用SuperTest测试HTTP接口的例子: ```javascript // 引入SuperTest和要测试的应用程序 var request = require('supertest'); var app = require('../app'); // 编写测试用例 describe('GET /', function() { it('should return "Hello, world!"', function(done) { request(app) .get('/') .expect(200) .expect('Hello, world!') .end(done); }); }); // app.js var express = require('express'); var app = express(); app.get('/', function(req, res) { res.send('Hello, world!'); }); module.exports = app; ``` 在上面的例子中,我们首先引入了SuperTest和要测试的应用程序app。接着,我们使用describe函数定义了一个测试套件,使用it函数定义了一个测试用例。在测试用例中,我们使用request函数模拟了一个GET请求,并使用expect函数断言响应的状态码应该为200,响应的内容应该为"Hello, world!"。最后,我们将app导出,以便在测试文件中引入。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值