如何模拟FileReader的失败

时间:2019-01-22 21:38:35

标签: typescript jasmine filereader

我有一个创建FileReader的函数。在该函数中,我还设置了loaderror事件处理程序

handleFileSelect(files:ArrayLike<File>){
...
      let reader = new FileReader()
      reader.onload = this.handleReaderLoaded;
      reader.onerror = this.handleReaderError;


      reader.readAsDataURL(file);
    }
  }

我想对handleFileSelect正确设置错误处理程序以及如果handleReaderError失败时调用错误处理程序(FileReader)进行单元测试。但是我不知道如何使FileReader失败。

到目前为止我写的规范是

fit('should call error handler when file doesn\'t get loaded successfully', (done) => {
    let newPracticeQuestionComponent = component;

    let file1 = new File(["foo1"], "foo1.txt");
    /*
    File reader will load the file asynchronously.
    The `done` method of `Jasmine` makes `Jasmine` wait
    When handleReaderError is called, call a fake function and within it call done
     */
    spyOn(newPracticeQuestionComponent,'handleReaderError').and.callFake(function(event:FileReaderProgressEvent){
      console.log("called fake implementation of handleReaderError ",event);
      expect(event.type).toEqual("abort");
      done();
    });

    newPracticeQuestionComponent.handleFileSelect([file1]);
//I SHOULD SIMULATE FILEREADER ERROR HERE BUT HOW??

  });

2 个答案:

答案 0 :(得分:1)

如果reader失败时onerror的行为正在调用readAsDataURL,则应该这样做:

spyOn(newPracticeQuestionComponent.reader, 'readAsDataURL').and.callFake(() => {
    newPracticeQuestionComponent.reader.onerror();
});

由于此操作将作为同步调用运行,因此您可以像下面这样简化在测试结束时的声明(遵循三元组A):

// Arrange
const newPracticeQuestionComponent = component;
spyOn(newPracticeQuestionComponent, 'handleReaderError');
spyOn(newPracticeQuestionComponent.reader, 'readAsDataURL').and.callFake(() => {
    newPracticeQuestionComponent.reader.onerror();
});
let file1 = new File(["foo1"], "foo1.txt");

// Act
newPracticeQuestionComponent.handleFileSelect([file1]);

// Assert
expect(newPracticeQuestionComponent.handleReaderError).toHaveBeenCalledWith({ type: 'abort' });

但是我不建议期望参数传递给函数event.type,因为它是我们当前未测试的另一个单元的规范。 (我们正在测试newPracticeQuestionComponent而不是reader调用事件错误的行为)


模拟reader的行为可能不是最好的方法。这取决于您要针对本机进行测试的内容。

如果我们想变得非常独立,newPracticeQuestionComponent应该不知道reader的行为,甚至包括回调错误,该单元唯一应该知道的就是设置onerror回调,您只需断言您已正确设置阅读器的onerror

// Arrange
const newPracticeQuestionComponent = component;
spyOn(newPracticeQuestionComponent.reader, 'readAsDataURL');
let file1 = new File(["foo1"], "foo1.txt");

// Act
newPracticeQuestionComponent.handleFileSelect([file1]);

// Assert
expect(newPracticeQuestionComponent.reader.onerror).toBe(newPracticeQuestionComponent.handleReaderError);

我不是测试方面的高手,但是在许多因素上编写上面和下面的示例一样的测试似乎是有利有弊。

希望这会有所帮助:)

答案 1 :(得分:1)

已经说过我们可以模拟 readAsDataURL 方法并从中分派错误事件。但是你的读者是函数handleFileSelect 中的一个局部变量。为了访问读取器,我们可以模拟 FileReader 构造函数并控制创建的文件读取器实例。 这里我使用 sinon 进行模拟:

// in your test:
...

// This is the reader instance that we have access
const reader = new FileReader()

// We throw an error in readAsArrayBuffer method of that instance
reader.readAsArrayBuffer = () => {
  reader.dispatchEvent(new Event('error'))
}

// Now make the constructor return our instance
sinon.stub(window, 'FileReader').returns(r)

// Now make your calls and assertions
...    

// Don't forget to restore the original constructor at the end
window.FileReader.restore()