I11*_*in8 10 javascript mocha.js promise should.js sails.js
因此,我对mocha完全不熟悉,并且我被要求编写集成测试,将表单数据发布到页面,获取身份验证密钥,然后对密钥运行测试.
我正确地获得了密钥,这可以通过我的日志声明来确认,但是当我运行mocha时,我的测试表示0传递.它甚至没有打印出'describe'和'it'语句的描述,暗示它们在promise中不起作用.有没有我可以这样工作,同时仍然让断言访问我的授权密钥?
require('should');
require('sails');
var Promise = require("promise");
var request = require('request');
describe('Domain Model', function(){
var options = { url:'link',
form:{
username: 'xxxxx@xxxxxx',
password: '0000'
},
timeout: 2000
};
//request auth key
var promise = new Promise(function(resolve,reject){
request.post(options, function(error, response, body){
//body contains the auth key, within a string of JSON
resolve(body);
});
});
//this is where I'm getting lost
promise.then(function(data,test){
var token = (JSON.parse(data))["access_token"];
console.log(token);
describe('Initialize',function(){
it('should be an string', function(){
(token).should.be.type('string');
});
});
});
});
Run Code Online (Sandbox Code Playgroud)
Ser*_*y K 21
Mocha无法找到您的测试,因为您没有正确构建它们.该it()
块应该立即在中describe()
块(和describe()
块可以相互嵌套,你认为合适).如果你想使用promises,承诺应该进入it()
块内,而不是相反.所以,作为第一遍,更新后的代码看起来应该是这样的(我为了简洁而省略了一些部分):
describe('Domain Model', function(){
var options = { ... };
describe('Initialize',function(){
it('should be an string', function(){
//request auth key
var promise = new Promise(function(resolve,reject){
// ...
});
promise.then(function(data,test){
var token = (JSON.parse(data))["access_token"];
console.log(token);
(token).should.be.type('string');
});
});
});
});
Run Code Online (Sandbox Code Playgroud)
请注意,承诺现在包含在主体内部it()
.摩卡现在应该能够找到你的考试.但是,它不会通过.为什么不?
您可能知道,承诺是异步的.使用mocha测试异步代码需要使用done
回调 - 有关详细信息,请参阅指南.基本上,这意味着it()
块应该接受一个名为的参数done
(名称很重要!).这个done
东西是mocha自动传递的东西 - 它的存在向mocha表明这个测试包含异步代码,因此它直到你这么说才完成执行.表明测试完成的方式是执行done
,因为done
实际上是一个回调函数.您应该done()
在您的测试被认为完成的任何时刻执行- 即,在任何代码块应该最后运行的末尾,在您的情况下,这是.then()
承诺的处理程序的底部.因此,改进我们的上一个版本,代码现在看起来像这样(再次,为简洁起见,切割一些部分):
describe('Domain Model', function(){
var options = { ... };
describe('Initialize',function(){
it('should be an string', function(done){
//request auth key
var promise = new Promise(function(resolve,reject){
// ...
});
promise.then(function(data,test){
var token = (JSON.parse(data))["access_token"];
console.log(token);
(token).should.be.type('string');
done();
});
});
});
});
Run Code Online (Sandbox Code Playgroud)
请注意,我刚刚添加了done
参数it()
,然后我在底部调用了它then()
.
在这一点上,代码应该工作,我想...我不确定,因为我无法测试它.但是,我们可以采取更多措施来进一步改进.
首先,我在这里质疑你对承诺的使用.如果您有一个用于获取访问令牌的API,那么我会选择让该API返回一个承诺,因为promises对调用者来说非常方便.但是,正如我相信您已经注意到,构建承诺可能有点单调乏味,我认为它不会为您的代码增加太多价值.我会选择这样做:
describe('Domain Model', function(){
var options = { ... };
describe('Initialize',function(){
it('should be an string', function(done){
//request auth key
request.post(options, function(error, response, body){
//body contains the auth key, within a string of JSON
var token = (JSON.parse(body))["access_token"];
console.log(token);
(token).should.be.type('string');
done();
});
});
});
});
Run Code Online (Sandbox Code Playgroud)
这不是那么短,更甜吗?代码仍然是异步的,因此您仍应确保您的it()
块接受done
回调,并且您应该在测试完成后调用它.
现在,如果你仍然坚持使用承诺,那么我还有一件事要警告你.如果.then()
处理程序代码中存在错误,会发生什么?好吧,根据文件:
如果被调用的处理程序抛出异常,那么.then返回的promise将被该异常拒绝.
你有承诺的拒绝处理程序吗?不,那是什么意思?这意味着错误将被无声地吞噬.你的测试将失败Error: timeout of 2000ms exceeded
,这是因为done
处理程序从未被调用过,但是错误的实际原因将不会显示出来,并且你会试着找出问题所在.
所以,你可以做什么?您可以使用第二个参数来.then()
指定拒绝处理程序,在那里,您可以利用done
mocha传入您的测试的回调接受错误参数的事实,因此如果您调用done("something")
,您的测试将失败(是我们在这种情况下想要的东西),而"东西"将是原因.所以这就是你的情况:
describe('Domain Model', function(){
var options = { ... };
describe('Initialize',function(){
it('should be an string', function(done){
//request auth key
var promise = new Promise(function(resolve,reject){
// ...
});
promise.then(function(data){
var token = (JSON.parse(data))["access_token"];
console.log(token);
(token).should.be.type('string');
done();
}, function (err) {
done(err);
});
});
});
});
Run Code Online (Sandbox Code Playgroud)
但是,我们可以做得更好.考虑如果从拒绝处理程序中抛出错误会发生什么.不太可能,因为你没有在那里做很多事 - 只是打电话done(err)
.但如果确实发生了怎么办?好吧,几乎是一样的 - 错误将被无声地吞噬,测试将失败并出现非特定timeout
错误,你将再次拔出你的头发.有没有办法可以让这个错误冒出来并重新投入?
事实上,有:Q和你正在使用的promise库都有一个名为的替代处理程序.done()
(不要与mocha的done
回调混淆).它与.then()
未捕获的异常类似,但行为略有不同.从文档:
承诺#done(onFulfilled,onRejected)
与.then相同的语义,除了它不返回promise并且重新抛出任何异常以便可以记录它们(在非浏览器环境中崩溃应用程序)
完美,这正是我们想要的.请务必了解何时应该使用.then()
,以及何时应该使用.done()
.该Q API做了解释的了出色的工作(和你正在使用的承诺库有类似的行为-我测试):
done
与then
使用相关的黄金法则是:将您的承诺退还给其他人,或者如果链条以您结束,请致电done
终止它.使用终止catch
是不够的,因为catch
处理程序本身可能会抛出错误.
(注意:.catch()
似乎是特定于Q的,但它与onRejected
回调非常相似,这是第二个参数.then()
.).
所以考虑到这一点,只需.then()
用一个替换你的鞋楦.done()
.当您使用时.done()
,您可以省略拒绝处理程序并依赖promise库重新抛出任何未处理的预期,因此您将获得错误描述和堆栈跟踪.考虑到上述情况,您的代码现在看起来像:
describe('Domain Model', function(){
var options = { ... };
describe('Initialize',function(){
it('should be an string', function(done){
//request auth key
var promise = new Promise(function(resolve,reject){
// ...
});
promise.done(function(data){
var token = (JSON.parse(data))["access_token"];
console.log(token);
(token).should.be.type('string');
done();
});
});
});
});
Run Code Online (Sandbox Code Playgroud)
基本上,忽略前面的代码示例,与之前的代码示例的唯一区别是我们使用的.done()
代替.then()
.
希望这涵盖了您开始所需的大部分内容.还有其他一些你可能想要考虑的事情,比如可能在before()
钩子而不是it()
块中检索auth键(因为我假设你正在测试的真实东西不是密钥的检索 - 这只是一个先决条件,测试你真正想测试的东西,所以钩子可能更合适 - 见这里).我还要问你是否应该从测试中连接到外部系统,而不仅仅是将其删除(这取决于它们是单元测试还是集成测试).我确信你可以提出一个更好的断言,只是检查这token
是一个字符串,就像使用正则表达式来确保它匹配一个模式,或实际测试一个受保护资源的请求并确保它通过.但我会留下这些问题供你思考.
归档时间: |
|
查看次数: |
8189 次 |
最近记录: |