我在网站上有一个简单的图像上传器和一个
javascript函数,它使用FileReader并将图像转换为base64,以便用户显示它而无需将其上传到实际的服务器.
function generateThumb(file) { var fileReader = new FileReader(); fileReader.readAsDataURL(file); fileReader.onload = function (e) { // Converts the image to base64 file.dataUrl = e.target.result; }; }
现在我正在尝试使用Mocha和Chai为这个方法编写测试.我的想法是,我想检查file.dataUrl是否已成功创建,它是否为base64.所以我想在测试环境中以某种方式模拟本地文件(不知道如何做到这一点).或者我根本不应该测试这个,并假设这是有效的?
解决方法
答案在这里取决于一点.您的“generateThumbs”方法是否具有除加载文件内容并将其分配给传入对象的属性之外的其他逻辑?或者它是否有其他逻辑,例如从图像数据生成缩略图,读出文件属性并将它们分配给文件对象?等等?
如果是这样,那么我建议您使用自己的模拟FileReader对象,以便控制测试结果.但是,它不是您要测试的FileReaders功能,它是您自己的逻辑.因此,您应该假设FileReader工作并测试依赖于它的代码是否有效.
现在,因为您发布的方法有点偏小,在这种情况下,我只是假设它有效,重命名方法并继续测试其余代码.但是有一个地方有这样的模拟,我必须承认弄清楚如何模拟事件目标是非常有趣的,所以我将在这里给出一个例子,使用你的方法作为基础:
//This implements the EventTarget interface //and let's us control when,where and what triggers events //and what they return //it takes in a spy and some fake return data var FakeFileReader = function(spy,fakeData) { this.listeners = {}; this.fakeData = fakeData; this.spy = spy; this.addEventListener('load',function () { this.spy.loaded = true; }); }; //Fake version of the method we depend upon FakeFileReader.prototype.readAsDataURL = function(file){ this.spy.calledReadAsDataURL = true; this.spy.file = file; this.result = this.fakeData; this.dispatchEvent({type:'load'}); //assume file is loaded,and send event }; FakeFileReader.prototype.listeners = null; FakeFileReader.prototype.addEventListener = function(type,callback) { if(!(type in this.listeners)) { this.listeners[type] = []; } this.listeners[type].push(callback); }; FakeFileReader.prototype.removeEventListener = function(type,callback) { if(!(type in this.listeners)) { return; } var stack = this.listeners[type]; for(var i = 0,l = stack.length; i < l; i++) { if(stack[i] === callback){ stack.splice(i,1); return this.removeEventListener(type,callback); } } }; FakeFileReader.prototype.dispatchEvent = function(event) { if(!(event.type in this.listeners)) { return; } var stack = this.listeners[event.type]; event.target = this; for(var i = 0,l = stack.length; i < l; i++) { stack[i].call(this,event); } }; // Your method function generateThumb(file,reader){ reader.readAsDataURL(file); reader.addEventListener('load',function (e) { file.dataUrl = base64(e.target.result); }); }
现在我们有一个很好的小对象,其行为类似于FileReader,但我们控制它的行为,现在我们可以使用我们的方法并将其注入,从而使我们能够使用这个模拟进行测试,并将真实的东西用于生产.
所以我们现在可以编写好的单元测试来测试它:
我假设你有mocha和chai设置
describe('The generateThumb function',function () { var file = { src: 'image.file'}; var readerSpy = {}; var testData = 'TESTDATA'; var reader = new FakeFileReader(readerSpy,testData); it('should call the readAsDataURL function when given a file name and a FileReader',function () { generateThumb(file,reader); expect(readerSpy.calledReadAsDataURL).to.be.true; expect(readerSpy.loaded).to.be.true; }); it('should load the file and convert the data to base64',function () { var expectedData = 'VEVTVERBVEE='; generateThumb(file,reader); expect(readerSpy.file.src).to.equal(file.src); expect(readerSpy.file.dataUrl).to.equal(expectedData); }); });
这是一个有效的JSFiddle示例:
https://jsfiddle.net/workingClassHacker/jL4xpwwv/2/
这里的好处是你可以创建这个模拟的几个版本:
>给出正确的数据会发生什么?
>给出不正确的数据会发生什么?
>从未调用回调时会发生什么?
>当放入太大的文件时会发生什么?
>当某种哑剧类型投入使用时会发生什么?
如果您需要的只是一个事件,您可以大规模简化模拟:
function FakeFileReader(spy,testdata){ return { readAsDataURL:function (file) { spy.file = file; spy.calledReadAsDataURL = true; spy.loaded = true; this.target = {result: testdata}; this.onload(this); } }; } function generateThumb(file,reader){ reader.onload = function (e) { file.dataUrl = base64(e.target.result); }; reader.readAsDataURL(file); }
我实际上是这样做的.并为不同目的创建其中几个.