[英]Testing non-promises after promise completes with Mocha, Chai and Sinon
我已經在Redux中創建了一個小型學習項目,並且基本上已經從文檔中復制了用於異步操作的中間件。 現在,我想為此編寫一些測試,以確保在我進行一些更改后它可以正常工作。
為了編寫測試,我使用的是Mocha,以及chai,chai-promise和sinon。
無論如何,我對redux都沒有問題,但是我不確定如何測試。
來自中間件的相關代碼:
export default function callApiMiddleware({ dispatch }) {
return next => action => {
// ... various checks
const [ requestType, successType, errorType ] = types;
dispatch({ ...payload, type: requestType });
return callApi().then(
response => dispatch({ ...payload, type: successType, response }),
error => dispatch({ ...payload, type: errorType, error })
);
}
}
無論承諾是否實現,中間件都會分派適當的操作。
為了測試這一點,我與其他人一起取消了調度功能,並且我還傳遞了一個虛假的承諾,即根據我要測試的內容來實現或拒絕。
我編寫的測試如下所示:
it('should trigger success action when successful', () => {
let promise = callApiMiddleware({ dispatch, getState })(next)({
...action,
callApi: () => new Promise((resolve, reject) => resolve('SUCCESS'))
});
return expect(promise).to.eventually.be.fulfilled;
});
這可以正常工作,但是我遇到的第一個問題是當我嘗試模擬可能由於沒有互聯網連接而導致的被拒絕的承諾時,所以我編寫了以下測試:
it('should trigger failure action when failure occurs', () => {
let promise = callApiMiddleware({ dispatch, getState })(next)({
...action,
callApi: () => new Promise((resolve, reject) => reject('ERROR'))
});
return expect(promise).to.eventually.be.rejected;
});
但這失敗,並顯示以下消息:
AssertionError:預期的諾言被拒絕,但未定義實現
預期的:[未定義]
實際的:[未定義]
這對我來說毫無意義,因為我明確地傳遞了一個承諾,那就是唯一的功能將被拒絕。
我的另一個問題是,我還想提出其他斷言,這些斷言與諾言本身沒有任何關系,但是必須在諾言完成時進行評估,例如,我想斷言dispatch
方法被調用了兩次。 在測試中,使用sinon對dispatch
方法本身進行了測試,以執行所需的斷言。 潛在地,我想以此方式做出多個斷言。
我嘗試了以下方法:
it('should trigger success action when successful', () => {
let promise = callApiMiddleware({ dispatch, getState })(next)({
...action,
callApi: () => new Promise((resolve, reject) => resolve('SUCCESS'))
});
return Q.all([
expect(promise).to.eventually.be.fulfilled,
expect(dispatch).to.eventually.be.calledTwice
]);
});
但是,這返回了一個非常大的錯誤,該錯誤告訴我dispatch
是thenable
即不是承諾。
我對如何執行此操作沒有任何想法,因此,我們將不勝感激。
諾言不會拋出錯誤,因此,如果您在第一個捕獲處理程序中捕獲到錯誤,除非再次拋出捕獲的錯誤,否則在下一個處理程序中將實現諾言。
// this does not work
promise.catch((e) => console.log(e)).catch((e) => console.log(e));
如果您希望這樣做,則必須重新拋出一個錯誤。
promise.catch((e) => {
console.log(e);
throw e;
}).catch((e) => console.log(e));
如果您希望測試通過,則需要重新拋出在promise的catch處理程序中捕獲的錯誤。 因此,您的代碼應如下所示:
export default function callApiMiddleware({ dispatch }) {
return next => action => {
// ... various checks
const [ requestType, successType, errorType ] = types;
dispatch({ ...payload, type: requestType });
return callApi().then(
response => dispatch({ ...payload, type: successType, response }),
error => {
dispatch({ ...payload, type: errorType, error });
throw error;
}
);
}
}
使用undefined
來實現Promise的原因是,這是中間件返回的內容:
return callApi().then(
response => dispatch({ ...payload, type: successType, response }),
error => dispatch({ ...payload, type: errorType, error })
);
由於它不會在第二個回調中拋出錯誤,因此可以實現最終的Promise。 由於它也不返回任何內容,因此可以使用undefined
來實現。
在這種情況下,您可以更改代碼以重新拋出錯誤:
return callApi().then(
response => dispatch({ ...payload, type: successType, response }),
error => {
dispatch({ ...payload, type: errorType, error })
throw error;
}
);
這將提供您期望的結果,但每次請求失敗時,都會在DevTools中報告未處理的拒絕。 在您的情況下可能很好。
至於第二個示例:
但是,這返回了一個非常大的錯誤,該錯誤告訴我派遣是不可行的,即不是承諾。
看起來.to.eventually.*
在Promises上起作用 。 確實, dispatch
不是一個承諾,所以您不能像這樣使用它。 您可能想編寫如下代碼:
return expect(promise).to.eventually.be.fulfilled.then(() => {
expect(dispatch).to.be.calledTwice();
});
最后,我鼓勵您查看Redux Saga 。 與自定義中間件相比,使用生成器描述副作用要容易得多,並且生成器更易於測試 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.