gpt4 book ai didi

javascript - 为什么这些测试通过了?

转载 作者:数据小太阳 更新时间:2023-10-29 04:43:25 25 4
gpt4 key购买 nike

我有这个功能:

let removePresentation = function(presentationName, callback) {
let rimraf = require('rimraf');

callback();
callback();
callback();

if(!presentationName || !presentationName.trim()) {
callback();
return;
}

presentationName = presentationName.replace('.zip', '');

rimraf('./presentations/' + presentationName, function(err) {
if(err) {
console.log(err);
}
callback();
});
};

exports.removePresentation = removePresentation;

我正在尝试使用以下内容对其进行测试:

var chai = require('chai'),
expect = require('chai').expect,
sinonChai = require('sinon-chai'),
sinon = require('sinon'),
mock = require('mock-require');

chai.use(sinonChai);

describe('removePresentation', function() {

var sandbox;
var callback;
var rimrafSpy;

beforeEach(function() {
sandbox = sinon.sandbox.create();
mock('../business/communications_business', {});

rimrafSpy = sinon.spy();
callback = sinon.spy();

mock('rimraf', rimrafSpy);
});

afterEach(function() {
sandbox.restore();
});

it('should call rimraf if presentation name is valid', function(done) {
let RoomStateBusiness = require('../business/roomstate_business');

RoomStateBusiness.removePresentation('name.zip', callback);

expect(rimrafSpy).to.have.been.calledWith('./presentations/name');
expect(callback).to.have.been.called.once;
done();
});

it('should not call rimraf if presentation name is null', function(done) {
let RoomStateBusiness = require('../business/roomstate_business');

RoomStateBusiness.removePresentation(null, callback);

expect(rimrafSpy).not.to.have.been.called;
expect(callback).to.have.been.called.once;
done();
});

it('should not call rimraf if presentation name is whitespace', function(done) {
let RoomStateBusiness = require('../business/roomstate_business');

RoomStateBusiness.removePresentation(' ', callback);

expect(rimrafSpy).not.to.have.been.called;
expect(callback).to.have.been.called.once;
done();
});

it('should not call rimraf if presentation name is empty string', function(done) {
let RoomStateBusiness = require('../business/roomstate_business');

RoomStateBusiness.removePresentation('', callback);

expect(rimrafSpy).not.to.have.been.called;
expect(callback).to.have.been.called.once;
done();
});

});

即使我多次调用 callback()(仅测试时),expect(callback).to.have.been.called.once; 始终断言为真。我已经检查了 Chai api,它期望调用正好是一次,尽管无论我调用 callback() 多少次它总是通过。我做错了什么?

最佳答案

没有expect(fn).to.have.been.called.once这样的断言。

根据 sinon-chai docs ,只有:

  • expect(fn).to.have.been.called
  • expect(fn).to.have.been.calledOnce

问题

这是 chai 的一个已知问题,也是为什么 getter-only-assertions 是一件坏事。 Chai 允许您编写一段看起来像属性访问的代码(即断言本身不以函数调用结束)来断言...无论您想要断言什么。这使用属性 getter 来执行必要的代码。

问题是,如果您输入错误或其他错误,表达式将简单地评估为 undefined(您正在访问一个不存在的属性)并且永远不会有任何断言代码执行,导致测试通过(因为只有在抛出异常时测试才会失败)。

在您的情况下,called 有一个断言,这很可能返回一个对象。不幸的是,该对象没有断言 once,因此没有执行任何代码并且测试通过。

解决方案

有 2 个选项可供您选择:

  • 升级到 Chai 4 和带有 Proxy 支持的 Node.js 版本(不确定在何处添加了 Proxy 支持,可能是 Node.js 5 或 6)- chai 通过代理所有内容来防止这些问题通过 Proxy 对象访问属性,该对象检查您是否使用有效的断言
  • 切勿将 getter 用于断言,并始终以函数调用结束断言 - 这将确保如果您犯了错误,测试将失败并出现臭名昭著的 undefined is not a function 错误

在我看来,第二种选择是首选,因为测试用例的正确性毋庸置疑。即使在受支持的平台上,仍然可以关闭 Chai 代理支持。

关于javascript - 为什么这些测试通过了?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45677127/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com