配置 javascript 单元测试和承诺断言
Configuring javascript unit testing and promises assertion
我是 javascript 单元测试的新手,但我相信至少对一般的单元测试有一点了解。
我正在尝试学习 'javascript way' 并开始为我的客户端代码编写单元测试。
为此,我安装了以下库:
mocha.js 和 chai.js
在一些令人惊讶的投票率中,一切都进行得很顺利。
我设法轻松地包含了这些东西并开始编写我的单元测试。
我在ASP核心顺便说一句。虽然我发现 VS2016 是我用过的这个 IDE 中漏洞最多的版本(但我只做了 5 年的专业人士,所以我可能是错的)有了新的 MVC 6 更改,它提供了一种简单的管理方法您的静态资源(或客户端依赖项),让您使用 bower 包管理器。
所以,回到测试。我从一小部分通用和简单的 javascript 函数开始。虽然写得有点差,但它们提供了很好的练习。
然而,过了一会儿我需要开始嘲笑。通过使用 C# 编写单元测试,我开始意识到这种类型的库的实用性。
由于这些概念绝不特定于 C#,而是一般的单元测试,我希望找到一个库来提供这种功能 - sinon.js。
再一次,一切都很顺利。
直到,我不得不嘲笑一个承诺。
同样,事实证明有一个库可以帮助我解决这个问题 - sinon-as-promised.js
经过相当多的努力,包括通过 npm 安装它,使用像 browserify 这样的工具将它解析成一个脚本以在浏览器中使用等等,我相信我设法得到它 运行ning。
此时我可以做类似的事情:
let returnsPromise = sinon.stub($, "ajax").resolves('success');
这将使我成为一个 "then-able" 对象(具有 then() 方法并且应该表现为承诺的对象)。
这里有一个小问题,它没有 .done() 和 .fail() 方法,这在我的编码中是众所周知的,但我猜想有一种简单的方法可以将它们扩展到对象中。
在那之后,当我读到 chai.js 提供了一种管理 promise expactations 的有效方法时,我什至开始印象深刻。
现在,我的问题来了。
我说的关于 chai 的是 "eventually" 支持。一个让我变魔术并避免在 then() 的成功和错误回调中使用 .done() 的词,只是为了确保我们不会在承诺中得到误报。
所以,应该这样使用:
it('testing eventually', function () {
let returnsPromise = sinon.stub($, "ajax").resolves('success');
return expect(returnsPromise()).should.eventually.equal('success');
});
如果没有成功获得想要的结果,这应该会失败。
现在,你可以想象当我无法像承诺的那样得到 chai 时我的失望 运行ning。
我找不到这个库的 'browser-friendly' 版本,所以,在使用 npm 安装它之后,再次将它浏览器化为 'supposed-to-be-working-in-the-browser-script' 我将它添加到聚会中。
但是,无论我做什么,在上面的示例中,我都会收到以下错误:
TypeError: Cannot read property 'equal' of undefined
at Context.<anonymous> (js/miscellaneous-tests.js:94:58)
我将其解释为 - 我们不知道您所说的 "eventually" 是什么意思。这让我相信我添加 chai-as-promised.js 的方式无效。
在这之后,我尝试了很多东西。有些愚蠢,有些甚至更愚蠢,但无论我尝试什么都无法让代码理解 "eventually"
这些东西包括:
- 阅读脚本并获取 chai-as-promised 的依赖项并将其添加到解决方案中(作为 browserify-ed 和来自 npm 的形式),在第二种情况下再次对它们的依赖项执行相同的操作- 直到我相信没有包裹丢失。
- 我尝试以多种不同的方式添加、删除文件我在写这篇文章时实际上是一片空白——但我能想到的每一种可能的组合——我都试过了。
- 我 googled "eventually is undefined" 和类似的东西很多次我觉得 google 有点生我的气,但我找不到我要找的东西
- 不知什么时候,我开始在地板上画一个大圆圈,里面有一个五角星,但这花了我一段时间(现在办公室里不容易找到处女之血和蜡烛之类的东西) 第二天我回到办公室时,清洁女工已将其擦除。
由于我没有想法,我希望你们中的一些人尝试过在浏览器中进行一些 javascript 单元测试。
因为它涉及相当多的资源、解释和东西,而且这个 post 已经比它应该的长了很多,我创建了一个 github 存储库,我在其中上传了我所有的东西到此为止。
这是一个 link:
js-unit-test-mocking
顺便说一句,如果您不喜欢 ASP 或任何与 Microsoft 相关的东西,运行 所需的一切都应该在 wwwroot 中。
谢谢你的包容。很抱歉 post.
这是一个 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);
});
在您的测试代码中,您混合了 expect
和 should
。
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');
您的代码有两个问题:
您正在同时使用 expect
和 should
界面 (expect(...).should.eventually.equal...)
。您应该使用其中之一,但不能同时使用两者。
您忘记使用 chai-as-promised
的导出值调用 chai.use
。我是从这样一个事实中推断出这一点的:如果我故意省略它,那么我会得到与你得到的完全相同的错误,而且我不知道有任何其他方法可以得到该错误。
无论您想做什么,您都可以将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
(这就是-s
选项可以)。输出在chai-as-promise-built.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="./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>
将所有内容打包成一个文件
这里的策略是使用 browserify 将所有内容编译到一个文件中。对于某些项目来说,这是一个可行的选择。对于希望使用 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);
行,您会收到与您在问题中报告的完全相同的错误消息。如果您确实更改了代码,请记住使用 browserify
进行重建。
我的意思是,您可以通过将 ajax 与 returns 和 jquery 延迟的函数打桩来使这种方式更简单。像下面这样的东西可以工作:
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;
我是 javascript 单元测试的新手,但我相信至少对一般的单元测试有一点了解。
我正在尝试学习 'javascript way' 并开始为我的客户端代码编写单元测试。
为此,我安装了以下库: mocha.js 和 chai.js
在一些令人惊讶的投票率中,一切都进行得很顺利。 我设法轻松地包含了这些东西并开始编写我的单元测试。
我在ASP核心顺便说一句。虽然我发现 VS2016 是我用过的这个 IDE 中漏洞最多的版本(但我只做了 5 年的专业人士,所以我可能是错的)有了新的 MVC 6 更改,它提供了一种简单的管理方法您的静态资源(或客户端依赖项),让您使用 bower 包管理器。
所以,回到测试。我从一小部分通用和简单的 javascript 函数开始。虽然写得有点差,但它们提供了很好的练习。
然而,过了一会儿我需要开始嘲笑。通过使用 C# 编写单元测试,我开始意识到这种类型的库的实用性。 由于这些概念绝不特定于 C#,而是一般的单元测试,我希望找到一个库来提供这种功能 - sinon.js。
再一次,一切都很顺利。
直到,我不得不嘲笑一个承诺。
同样,事实证明有一个库可以帮助我解决这个问题 - sinon-as-promised.js
经过相当多的努力,包括通过 npm 安装它,使用像 browserify 这样的工具将它解析成一个脚本以在浏览器中使用等等,我相信我设法得到它 运行ning。
此时我可以做类似的事情:
let returnsPromise = sinon.stub($, "ajax").resolves('success');
这将使我成为一个 "then-able" 对象(具有 then() 方法并且应该表现为承诺的对象)。 这里有一个小问题,它没有 .done() 和 .fail() 方法,这在我的编码中是众所周知的,但我猜想有一种简单的方法可以将它们扩展到对象中。
在那之后,当我读到 chai.js 提供了一种管理 promise expactations 的有效方法时,我什至开始印象深刻。
现在,我的问题来了。
我说的关于 chai 的是 "eventually" 支持。一个让我变魔术并避免在 then() 的成功和错误回调中使用 .done() 的词,只是为了确保我们不会在承诺中得到误报。
所以,应该这样使用:
it('testing eventually', function () {
let returnsPromise = sinon.stub($, "ajax").resolves('success');
return expect(returnsPromise()).should.eventually.equal('success');
});
如果没有成功获得想要的结果,这应该会失败。
现在,你可以想象当我无法像承诺的那样得到 chai 时我的失望 运行ning。
我找不到这个库的 'browser-friendly' 版本,所以,在使用 npm 安装它之后,再次将它浏览器化为 'supposed-to-be-working-in-the-browser-script' 我将它添加到聚会中。
但是,无论我做什么,在上面的示例中,我都会收到以下错误:
TypeError: Cannot read property 'equal' of undefined
at Context.<anonymous> (js/miscellaneous-tests.js:94:58)
我将其解释为 - 我们不知道您所说的 "eventually" 是什么意思。这让我相信我添加 chai-as-promised.js 的方式无效。
在这之后,我尝试了很多东西。有些愚蠢,有些甚至更愚蠢,但无论我尝试什么都无法让代码理解 "eventually"
这些东西包括:
- 阅读脚本并获取 chai-as-promised 的依赖项并将其添加到解决方案中(作为 browserify-ed 和来自 npm 的形式),在第二种情况下再次对它们的依赖项执行相同的操作- 直到我相信没有包裹丢失。
- 我尝试以多种不同的方式添加、删除文件我在写这篇文章时实际上是一片空白——但我能想到的每一种可能的组合——我都试过了。
- 我 googled "eventually is undefined" 和类似的东西很多次我觉得 google 有点生我的气,但我找不到我要找的东西
- 不知什么时候,我开始在地板上画一个大圆圈,里面有一个五角星,但这花了我一段时间(现在办公室里不容易找到处女之血和蜡烛之类的东西) 第二天我回到办公室时,清洁女工已将其擦除。
由于我没有想法,我希望你们中的一些人尝试过在浏览器中进行一些 javascript 单元测试。
因为它涉及相当多的资源、解释和东西,而且这个 post 已经比它应该的长了很多,我创建了一个 github 存储库,我在其中上传了我所有的东西到此为止。
这是一个 link: js-unit-test-mocking
顺便说一句,如果您不喜欢 ASP 或任何与 Microsoft 相关的东西,运行 所需的一切都应该在 wwwroot 中。
谢谢你的包容。很抱歉 post.
这是一个 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);
});
在您的测试代码中,您混合了 expect
和 should
。
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');
您的代码有两个问题:
您正在同时使用
expect
和should
界面 (expect(...).should.eventually.equal...)
。您应该使用其中之一,但不能同时使用两者。您忘记使用
chai-as-promised
的导出值调用chai.use
。我是从这样一个事实中推断出这一点的:如果我故意省略它,那么我会得到与你得到的完全相同的错误,而且我不知道有任何其他方法可以得到该错误。
无论您想做什么,您都可以将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
(这就是-s
选项可以)。输出在chai-as-promise-built.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="./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>
将所有内容打包成一个文件
这里的策略是使用 browserify 将所有内容编译到一个文件中。对于某些项目来说,这是一个可行的选择。对于希望使用 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);
行,您会收到与您在问题中报告的完全相同的错误消息。如果您确实更改了代码,请记住使用 browserify
进行重建。
我的意思是,您可以通过将 ajax 与 returns 和 jquery 延迟的函数打桩来使这种方式更简单。像下面这样的东西可以工作:
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;