配置javascript单元测试并承诺断言

时间:2016-11-17 12:59:25

标签: javascript unit-testing mocking sinon chai

我是javascript单元测试的新手,但我相信至少对单元测试有一点认识。

我正在尝试学习“javascript方式”#39;并开始为我的客户端代码编写单元测试。

为此,我安装了以下库: mocha.js和chai.js

在一些令人惊讶的投票率中,情况一切顺利。 我设法轻松地包含这些东西并开始编写我的单元测试。

我在ASP Core btw工作。虽然我发现VS2016是我曾经使用过的这个IDE的最错误的版本(但我已经专业5年了,所以我可能错了)使用新的MVC 6更改它提供了一种简单的方法来管理您的静态资源(允许您使用bower包管理器。或者客户端依赖项。

所以,回到测试阶段。我从一小部分通用和简单的javascript函数开始,我已经开始了。虽然写得不好,但他们提供了很好的锻炼。

然而,过了一段时间我需要开始嘲笑。通过在C#中编写单元测试,我开始意识到这种类型库的有用性。 由于这些概念并非特定于C#,而是一般的单元测试,我期望找到一个能提供这种功能的库 - sinon.js。

所以,一切都进展顺利。

直到,我不得不嘲笑一个承诺。

再次证明,有一个库可以帮助我解决这个问题 - sinon-as-promised.js

经过一段时间的努力,通过npm安装它,使用像browserify这样的工具把它解析成一个在浏览器中使用的单个脚本,我相信我设法让它运行起来。

此时我可以做类似的事情:

let returnsPromise = sinon.stub($, "ajax").resolves('success');

这将使我成为一个"然后能够" object(具有then()方法并且应该表现为promise的东西)。 这里有一个小问题,它没有.done()和.fail()方法,我在编码时更喜欢这些方法,但我猜测有一种简单的方法可以将它们扩展到对象中。

在那之后,当我读到chai.js提供一种管理承诺表达的有效方式时,我甚至开始感到印象深刻。

在我的问题上,我们就是这样。

我正在谈论的关于柴的事情是"最终"支持。这个词让我做了魔术,并且无需在then()的成功和错误回调中使用.done(),只是为了确保我们没有在promise中得到误报。

所以,它应该像这样使用:

it('testing eventually', function () {
    let returnsPromise = sinon.stub($, "ajax").resolves('success');
    return expect(returnsPromise()).should.eventually.equal('success');        
});

如果除了想要的结果成功之外发生任何事情,这应该会失败。

现在,当我无法按照承诺运行时,你可以想象我的失望。

我无法找到适合浏览器的浏览器。这个库的版本,所以,再次使用npm安装它之后,将其浏览到一个“应该在浏览器中工作”的脚本'我把它添加到派对上。

但是,无论我做什么,在上面的示例中,我都会收到以下错误:

TypeError: Cannot read property 'equal' of undefined
at Context.<anonymous> (js/miscellaneous-tests.js:94:58)

我认为 - 我们不知道你的意思&#34;最终&#34;。这让我相信我添加chai-as-promised.js的方式不起作用。

在此之后,我尝试了很多东西。有些愚蠢,有些甚至更多,但无论我尝试过什么都不能让代码理解&#34;最终&#34;

这些事情包括:

  • 阅读脚本并获取并添加chai-as-promised的依赖关系(包括浏览器化和来自npm的形式),并在第二个场景中再次为依赖关系做同样的事情 - 直到我相信没有包丢失。
  • 我尝试添加,以多种不同的方式删除文件,我实际上是在写这篇文章时画了一个空白 - 但我能想到的每一种可能的组合 - 我试过了。
  • 我用Google搜索&#34;最终未定义&#34;和我这么多次的东西我认为谷歌有点生气,但我无法找到我想要的东西
  • 在某些时候,我开始在地板上绘制一个带有五角星形的大圆圈,但它花了我一段时间(像处女的血和蜡烛在现在的办公室里很容易找到)当我第二天回到办公室时,清洁工已经擦掉了它。

由于我没有想法,我希望你们中的一些人尝试在浏览器中进行一些javascript单元测试。

因为它涉及相当多的资源,解释和内容,并且这篇文章已经比它应该的时间更长了,我创建了一个github存储库,我已经上传了迄今为止所做的一切。

这是一个指向它的链接: js-unit-test-mocking

顺便说一下,如果你没有使用ASP或任何与微软相关的东西,那么运行它所需的一切都应该在wwwroot中。

感谢您对我的承诺。对不起,很长的帖子。

3 个答案:

答案 0 :(得分:2)

您的代码存在两个问题:

  1. 您正在使用expectshould个界面(expect(...).should.eventually.equal...)。您应该同时使用其中一个,但不能同时使用两个。

  2. 您忘记使用chai.use的导出值拨打chai-as-promised。我推断这个事实,如果我故意省略这个,那么我得到完全相同的错误,我不知道有任何其他方法来获得该错误。

  3. 无论您想做什么,转换chai-as-promised以在浏览器中工作。既然你提到使用browserify,我会在答案中使用它。您可以使用webpack甚至编写自己的脚本来进行转换。

    接下来是两个一般策略。

    仅转换chai-as-promised

    此处的策略是将所有内容分开,只将chai-as-promised转换为在浏览器中运行。这是一个说明性的测试文件:

    const expect = chai.expect;
    mocha.setup("bdd");
    
    chai.should();
    
    // Commenting out this line reproduces the exact error message
    // reported in the question.
    chai.use(chaiAsPromised);
    
    // Incorrect use of should with expect.
    it('testing eventually incorrectly', function () {
        return expect(Promise.resolve("success")).should.eventually.equal('success');
    });
    
    // Correct use of expect alone.
    it('testing eventually with expect', function () {
        return expect(Promise.resolve("success")).eventually.equal('success');
    });
    
    // Correct use of should alone.
    it('testing eventually with should', function () {
        return Promise.resolve("success").should.eventually.equal('success');
    });
    
    使用此命令转换

    chai-as-promised

    browserify -o chai-as-promised-built.js -s chaiAsPromised node_modules/chai-as-promised/lib/chai-as-promised.js
    

    这基本上需要chai-as-promised.js并将其包装到代码中,以便它在CommonJS方言中正常导出的内容成为浏览器中的全局导出,并且全局导出名为chaiAsPromised(这就是{ {1}}选项确实)。输出位于-s,这是您需要在浏览器中加载的内容。

    然后您可以使用此chai-as-promise-built.js文件:

    index.html

    将所有内容捆绑成一个文件

    这里的策略是使用browserify将所有内容编译成单个文件。对于某些项目,这是一个可行的选择。对于希望使用<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/xhtml; charset=utf-8"/> <link href="./node_modules/mocha/mocha.css" type="text/css" media="screen" rel="stylesheet" /> <script type="text/javascript" src="./node_modules/mocha/mocha.js"></script> <script type="text/javascript" src="./node_modules/chai/chai.js"></script> <script type="text/javascript" src="./chai-as-promised-built.js"></script> <script type="text/javascript" src="./test.js"></script> </head> <body> <div id="mocha"></div> <script> mocha.run(); </script> </body> </html> 编写代码而不是依赖于全局变量的项目,它也可能更受欢迎。这是一个说明性的测试文件:

    require

    安装所需模块后,使用以下命令构建它:

    const chai = require("chai");
    const chaiAsPromised = require("chai-as-promised");
    const expect = chai.expect;
    const mocha = require("mocha");
    mocha.mocha.setup("bdd");
    
    chai.should();
    
    // Commenting out this line reproduces the exact error message
    // reported in the question.
    chai.use(chaiAsPromised);
    
    // Incorrect use of should with expect.
    it('testing eventually incorrectly', function () {
        return expect(Promise.resolve("success")).should.eventually.equal('success');
    });
    
    // Correct use of expect alone.
    it('testing eventually with expect', function () {
        return expect(Promise.resolve("success")).eventually.equal('success');
    });
    
    // Correct use of should alone.
    it('testing eventually with should', function () {
        return Promise.resolve("success").should.eventually.equal('success');
    });
    

    然后您可以使用此browserify -o built.js test.js 文件加载它:

    index.html

    您将看到第一个测试失败,因为它一起尝试使用<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/xhtml; charset=utf-8"/> <link href="./node_modules/mocha/mocha.css" type="text/css" media="screen" rel="stylesheet" /> <script type="text/javascript" src="./built.js"></script> </head> <body> <div id="mocha"></div> <script> mocha.run(); </script> </body> expect。随后的两个测试将通过。

    如果您注释掉should行,则会得到与您在问题中报告的内容完全相同的错误消息。如果您更改了代码,请记住使用chai.use(chaiAsPromised);重建。

答案 1 :(得分:1)

我的意思是,你可以通过使用返回jquery延迟的函数来存储ajax来使这种方式变得更简单。像下面这样的东西可以工作:

var dfd = $.Deferred();
var callback = sinon.spy();
sinon.stub($, "ajax", function() {
   return dfd.promise();
})
$.ajax('...').done(callback);
dfd.resolve();
expect(callback).should.have.been.called();

你也可以创建一个帮助你的帮助器,以及一个总是用原始函数替换ajax的“afterEach”。

上述代码取决于https://github.com/domenic/sinon-chai。如果你不想依赖sinon-chai那么你可以只看一个间谍的“callCount”。像这样:

expect(callback.callCount > 0).to.be.ok;

答案 2 :(得分:0)

以下是chaiAsPromised expect测试模式:

var chai = require("chai");
var expect = chai.expect;
var chaiAsPromised = require("chai-as-promised");
chai.use(chaiAsPromised);

it("promise should return blah", function() {
  var blah = "blah";

  var result = somethingToTest();

  return expect(result).to.eventually.equal(blah);
});

在您的测试代码中,您混合了expectshould

return expect(returnsPromise()).should.eventually.equal('success');

修改:来自Chai API文档:Chai Assertions for Promises

return doSomethingAsync().should.eventually.equal("foo");

遵循相同的模式,您的代码应为:

return returnsPromise().should.eventually.equal('success');