使用mocha和html5文件api进行Javascript测试?

使用mocha和html5文件api进行Javascript测试?,javascript,mocha.js,filereader,html5-filesystem,Javascript,Mocha.js,Filereader,Html5 Filesystem,我在一个网站上有一个简单的图像上传程序和一个javascript函数,它使用FileReader,并将图像转换为base64来显示给用户,而无需上传到实际的服务器 function generateThumb(file) { var fileReader = new FileReader(); fileReader.readAsDataURL(file); fileReader.onload = function (e) { // Converts the

我在一个网站上有一个简单的图像上传程序和一个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
为这种方法编写测试。我的想法是,我想检查
文件.dataUrl
是否已成功创建,并且它是base64。所以我想在测试环境中模拟本地文件(不知道如何实现)。或者我根本不应该测试它,并假设它正在工作?

这里的答案取决于一点。“generateThumbs”方法除了加载文件内容并将其分配给传入对象的属性之外,还有其他逻辑吗?或者它是否具有其他逻辑,例如从图像数据生成缩略图、读取文件属性并将其分配给文件对象?等等

如果是这样的话,我实际上建议您用自己的对象模拟FileReader对象,这样您就可以控制测试结果。但是,您要测试的不是FileReader功能,而是您自己的逻辑。所以,您应该假设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);
    });

}
下面是一个正在工作的JSFIDLE示例:

这里的好处是,您可以创建此模拟的多个版本:

  • 当给出正确的数据时会发生什么
  • 当给出不正确的数据时会发生什么
  • 当从未调用回调时会发生什么
  • 当文件太大时会发生什么
  • 当放入某个mime类型时会发生什么
当然,如果您只需要一个事件,就可以大大简化模拟:

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);
}
我就是这样做的。并为不同的目的创建其中的几个

简单版本:

我也在想同样的事情。
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);
}