【问题标题】:how to mock failure of FileReader如何模拟 FileReader 的失败
【发布时间】:2019-01-22 21:38:35
【问题描述】:

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

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


      reader.readAsDataURL(file);
    }
  }

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

  });

【问题讨论】:

  • 你能找到一个好的解决方案吗?
  • 我得到了FileReader 的引用并使用dispatchEvent 来模拟错误reader.dispatchEvent(new Event('error'));。您是否尝试过下面 mixth 提供的答案?
  • 我看到了,但不能完全理解。你是如何在你的函数中引用FileReader的?
  • 我在这里问了一个类似但不同的问题 - 您的解决方案也适用于我的情况吗? stackoverflow.com/questions/65806605/…

标签: typescript jasmine filereader


【解决方案1】:

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

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);

我不是测试大师,但在许多因素上编写像上面和下面的例子这样的测试似乎是利弊。

希望这会有所帮助:)

【讨论】:

  • 谢谢。 reader 是函数 handleFileSelect 的局部变量。我做不到newPracticeQuestionComponent.reader
  • 那你如何创建reader?你可以用这种方式模拟它们。
  • 我暂时从handleFileSelect返回reader的实例,然后用reader.dispatchEvent('error')模拟报错。这不是最好的解决方法,因为我的代码同时获得了 loaderror 事件,但至少我能够测试 error 是否有效
  • 据我了解,测试应该影响我们设计软件的方式,而不是弯曲软件本身以使测试更容易。这个reader什么时候初始化?例如,如果newPracticeQuestionComponent 通过调用ReaderService.get() 得到reader,那么我们可以从那里创建一个模拟reader
  • 我同意,这也不是我的偏好,但我找不到替代方案。 readerhandleFileSelect 中创建。工作流程是读取用户选择的文件(使用input html 标签),然后将其显示为缩略图。我真的不需要handleFileSelect 函数之外的阅读器实例。
【解决方案2】:

已经说过我们可以模拟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()

【讨论】:

    猜你喜欢
    • 2020-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-05
    • 2018-03-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多