如何测试 fetch api 中的网络错误?
How can I test network errors in fetch api?
我已经成功地在我一直致力于学习 ES6 的简单应用程序上测试已解决的承诺,但在测试可能存在网络错误的情况时遇到了问题。
我写了这个测试用例:
import {Weather} from '../js/weather';
import chai from 'chai';
import sinon from 'sinon';
import * as chaiAsPromised from 'chai-as-promised';
chai.use(chaiAsPromised);
let assert = chai.assert;
let should = chai.should;
describe('weatherbot-1', function () {
beforeEach(function () {
sinon.stub(window, 'fetch');
let data = '{"cod": "400", "message": "Nothing to geocode"}';
let res = new window.Response(data, {
ok: false,
status: 400,
headers: {
'Content-type': 'application/json'
}
});
window.fetch.returns(Promise.reject(res));
});
afterEach(function () {
window.fetch.restore();
});
it('should ensure that promise is rejected', function () {
let weather = new Weather(0, 0);
return assert.isRejected(weather.getWeather(), 'Rejected');
});
});
有问题的方法是:
getWeather() {
let headers = new Headers();
let init = {
method: 'GET',
headers: headers,
cache: 'default'
};
let url = 'http://localhost:8080/weather?lat=' + '' + '&lon=' + this.longitude;
return fetch(url, init).then(function (response) {
return response.json();
}).catch((error) => {
return error;
});
}
为了测试承诺,我使用 chai-as-promised
& chai
和 mocha
& sinon
来存根 fetch
api。
每当我 运行 测试时,我都会收到此错误:
AssertionError: expected promise to be rejected with an error including 'Rejected' but it was fulfilled with { type: 'default',
url: '',
redirected: false,
status: 400,
ok: false,
statusText: 'OK',
headers:
{ append: [Function: append],
delete: [Function: delete],
get: [Function: get],
getAll: [Function: getAll],
has: [Function: has],
set: [Function: set],
keys: [Function: keys],
values: [Function: values],
entries: [Function: entries],
forEach: [Function: forEach] },
body: {},
bodyUsed: false,
clone: [Function: clone],
arrayBuffer: [Function: arrayBuffer],
blob: [Function: blob],
json: [Function: json],
text: [Function: text] }
从外观上看,Promise.reject()
可能无法正常工作。还有其他方法可以测试网络错误吗?
问题出在getWeather
,而不是测试:
return fetch(url, init)
.then(function (response) {
return response.json();
})
.catch((error) => {
return error;
})
Promise#catch
returns a resolved Promise,因为它的工作是处理错误。应用程序的其余部分应该能够在收到拒绝后正常运行,就像 try/catch
.
如果你想让拒绝到达测试,你的代码不应该赶上拒绝:
return fetch(url, init)
.then(function (response) {
return response.json();
})
一般来说,您应该只 catch
可以正确处理错误的地方。在此示例中,您可能希望在可以显示错误消息的视图中处理拒绝。
此外,您的代码对无效情况进行了建模。 fetch
return已解决承诺所有有效的 HTTP 响应,包括非 200 状态。
当它根本无法建立连接时它会拒绝,例如fetch("http://sdfdsfsd")
。在这种情况下,它拒绝 Error
对象。
要正确测试 fetch
拒绝,您应该模拟这种情况并让存根 return Promise.reject(new Error("a message"))
.
getWeather
中的 catch 子句函数 returns 一个新的、已实现的承诺。基本上,catch 会剥夺您测试拒绝的能力。您可以 做的是,使用间谍作为拒绝处理程序,然后测试它是否被调用。
我已经成功地在我一直致力于学习 ES6 的简单应用程序上测试已解决的承诺,但在测试可能存在网络错误的情况时遇到了问题。
我写了这个测试用例:
import {Weather} from '../js/weather';
import chai from 'chai';
import sinon from 'sinon';
import * as chaiAsPromised from 'chai-as-promised';
chai.use(chaiAsPromised);
let assert = chai.assert;
let should = chai.should;
describe('weatherbot-1', function () {
beforeEach(function () {
sinon.stub(window, 'fetch');
let data = '{"cod": "400", "message": "Nothing to geocode"}';
let res = new window.Response(data, {
ok: false,
status: 400,
headers: {
'Content-type': 'application/json'
}
});
window.fetch.returns(Promise.reject(res));
});
afterEach(function () {
window.fetch.restore();
});
it('should ensure that promise is rejected', function () {
let weather = new Weather(0, 0);
return assert.isRejected(weather.getWeather(), 'Rejected');
});
});
有问题的方法是:
getWeather() {
let headers = new Headers();
let init = {
method: 'GET',
headers: headers,
cache: 'default'
};
let url = 'http://localhost:8080/weather?lat=' + '' + '&lon=' + this.longitude;
return fetch(url, init).then(function (response) {
return response.json();
}).catch((error) => {
return error;
});
}
为了测试承诺,我使用 chai-as-promised
& chai
和 mocha
& sinon
来存根 fetch
api。
每当我 运行 测试时,我都会收到此错误:
AssertionError: expected promise to be rejected with an error including 'Rejected' but it was fulfilled with { type: 'default',
url: '',
redirected: false,
status: 400,
ok: false,
statusText: 'OK',
headers:
{ append: [Function: append],
delete: [Function: delete],
get: [Function: get],
getAll: [Function: getAll],
has: [Function: has],
set: [Function: set],
keys: [Function: keys],
values: [Function: values],
entries: [Function: entries],
forEach: [Function: forEach] },
body: {},
bodyUsed: false,
clone: [Function: clone],
arrayBuffer: [Function: arrayBuffer],
blob: [Function: blob],
json: [Function: json],
text: [Function: text] }
从外观上看,Promise.reject()
可能无法正常工作。还有其他方法可以测试网络错误吗?
问题出在getWeather
,而不是测试:
return fetch(url, init)
.then(function (response) {
return response.json();
})
.catch((error) => {
return error;
})
Promise#catch
returns a resolved Promise,因为它的工作是处理错误。应用程序的其余部分应该能够在收到拒绝后正常运行,就像 try/catch
.
如果你想让拒绝到达测试,你的代码不应该赶上拒绝:
return fetch(url, init)
.then(function (response) {
return response.json();
})
一般来说,您应该只 catch
可以正确处理错误的地方。在此示例中,您可能希望在可以显示错误消息的视图中处理拒绝。
此外,您的代码对无效情况进行了建模。 fetch
return已解决承诺所有有效的 HTTP 响应,包括非 200 状态。
当它根本无法建立连接时它会拒绝,例如fetch("http://sdfdsfsd")
。在这种情况下,它拒绝 Error
对象。
要正确测试 fetch
拒绝,您应该模拟这种情况并让存根 return Promise.reject(new Error("a message"))
.
getWeather
中的 catch 子句函数 returns 一个新的、已实现的承诺。基本上,catch 会剥夺您测试拒绝的能力。您可以 做的是,使用间谍作为拒绝处理程序,然后测试它是否被调用。