我有一个创建
FileReader
的函数。在该函数中,我还设置了 load
和 error
事件处理程序
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??
});
如果
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);
我不是测试方面的专家,但根据许多因素编写上面和下面的示例测试似乎是有利有弊的。
希望这有帮助:)
已经说过,我们可以模拟
readAsDataURL
方法并从中分派错误事件。但你的 reader 是函数 handleFileSelect
中的局部变量。为了访问读取器,我们可以模拟 FileReader
构造函数并控制创建的文件读取器实例。
这里我使用sinon来进行mocking:
// 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()
当您有一个打字稿文件并根据从磁盘读取输入文件的成功情况来设置严重性时:
enum Severity
{
NONE = 'none',
ERROR = 'danger',
OK = 'success'
}
private jsonFile: File | undefined = undefined;
private severity: Severity = Severity.NONE;
protected changeFileSelection(): void
{
this.jsonFile = this.input.files?.[0];
const fileReader: FileReader = new FileReader();
fileReader.onload = () => this.load(JSON.parse(fileReader.result as string));
fileReader.onerror = (error: ProgressEvent<FileReader>): void => {
this.severity = Severity.ERROR;
console.error(error);
};
this.severity = Severity.OK;
fileReader.readAsText(this.jsonFile, 'UTF-8');
}
您可以在 Jasmine 中测试 onerror 调用,如下所示:
it('should handle file read errors', () => {
const emptyFile: File = new File(['{}'], 'filename.json');
component['jsonFile'] = emptyFile;
const dataTransfer: DataTransfer = new DataTransfer();
dataTransfer.items.add(emptyFile);
input.files = dataTransfer.files; // @see https://stackoverflow.com/a/68182158/959484
const fileReader: FileReader = new FileReader();
spyOn(window, 'FileReader').and.returnValue(fileReader);
spyOn(fileReader, 'readAsText').and.callFake((): void => {
expect(component['severity']).toEqual(component['Severity'].OK);
fileReader.dispatchEvent(new Event('error'));
});
component['changeFileSelection']();
expect(component['severity']).toEqual(component['Severity'].ERROR);
});
请注意,
readAsText
调用必须在您希望成功读取的正严重性结果之后。但在这个测试用例中,由于读取时出现模拟错误,结果将为负。