亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

我如何在 React 組件中模擬服務以開玩笑地隔離單元測試?

我如何在 React 組件中模擬服務以開玩笑地隔離單元測試?

皈依舞 2022-12-22 09:56:09
我正在嘗試重構一個單元測試,以將使用 axios 調用 API 的服務與調用該服務的組件隔離開來。該服務目前非常簡單:import axios from 'axios'export default class SomeService {  getObjects() {    return axios.get('/api/objects/').then(response => response.data);  }}這是調用該服務的組件的片段:const someService = new SomeService();class ObjectList extends Component {  state = {    data: [],  }  componentDidMount() {    someService.getObjects().then((result) => {      this.setState({        data: result,      });    });  }  render() {    // render table rows with object data  }}export default ObjectList我可以通過模擬 axios 來測試 ObjectList 是否按照我的預期呈現數據:// ...jest.mock('axios')const object_data = {  data: require('./test_json/object_list_response.json'),};describe('ObjectList', () => {  test('generates table rows from object api data', async () => {    axios.get.mockImplementationOnce(() => Promise.resolve(object_data));    const { getAllByRole } = render(      <MemoryRouter>        <table><tbody><ObjectList /></tbody></table>      </MemoryRouter>    );    await wait();    // test table contents  });});一切都順利通過。作為主要的學術練習,我試圖弄清楚如何模擬 SomeService 而不是 axios,這就是事情出錯的地方,因為我認為我對正在傳遞的內容的內部結構了解不夠。例如,我認為由于 SomeService 只返回 axios 響應,我可以類似地模擬 SomeService,有點像這樣:// ...const someService = new SomeService();jest.mock('./SomeService')const object_data = {  data: require('./test_json/object_list_response.json'),};describe('ObjectList', () => {  test('generates table rows from object api data', async () => {    someService.getObjects.mockImplementationOnce(() => Promise.resolve(object_data))// etc.這失敗并出現錯誤:Error: Uncaught [TypeError: Cannot read property 'then' of undefined],錯誤從以下位置追溯到這一行ObjectList:someService.getObjects().then((result) => {我具體需要模擬ObjectList什么,以便組件可以獲取SomeService設置其狀態所需的內容?
查看完整描述

3 回答

?
倚天杖

TA貢獻1828條經驗 獲得超3個贊

模擬類實例的問題在于,如果沒有引用,可能很難訪問類實例及其方法。由于someService是組件模塊的本地文件,因此無法直接訪問。


沒有特定的模擬,jest.mock('./SomeService')依賴于 以未指定的方式工作的類自動模擬。該問題表明模擬類的不同實例具有不同的getObjects模擬方法,這些方法不會相互影響,盡管getObjects是原型方法并且符合new SomeService().getObjects === new SomeService().getObjects未模擬類。


解決方案是不依賴自動模擬,而是讓它按照預期的方式工作。使模擬方法可在類實例外部訪問的一種實用方法是將其與模擬模塊一起使用。這種方式mockGetObjects.mockImplementationOnce會影響現有的someService. mockImplementationOnce暗示該方法可以稍后在每個測試中更改實現:


import { mockGetObjects }, SomeService from './SomeService';


jest.mock('./SomeService', () => {

  let mockGetObjects = jest.fn();

  return {

    __esModule: true,

    mockGetObjects,

    default: jest.fn(() => ({ getObjects: mockGetObjects }))

  };

});


...


mockGetObjects.mockImplementationOnce(...);

// instantiate the component

如果該方法應該有常量模擬實現,這會簡化任務,因為可以在jest.mock. 暴露mockGetObjects斷言可能仍然是有益的。


查看完整回答
反對 回復 2022-12-22
?
桃花長相依

TA貢獻1860條經驗 獲得超8個贊

在使用 jest 文檔中建議的不同方法進行一些試驗和錯誤嘗試后,唯一似乎有效的方法是jest.mock()使用模塊工廠參數進行調用,如下所示:


// rename data to start with 'mock' so that the factory can use it

const mock_data = {

  data: require('./test_json/object_list_response.json'),

};


jest.mock('./SomeService', () => {

  return jest.fn().mockImplementation(() => {

    return {

      getObjects: () => {

        return Promise.resolve(mock_data).then(response => response.data)

      }

    };

  });

});


// write tests

使用mockResolvedValue()沒有用,因為我無法鏈接.then()它。


如果這導致任何人找到更優雅或慣用的解決方案,我歡迎其他答案。


查看完整回答
反對 回復 2022-12-22
?
慕的地10843

TA貢獻1785條經驗 獲得超8個贊

對于后代,另一種解決方案是在文件夾中創建手動模擬__mocks__(靈感來自 Estus Flask 的評論和本文檔)。


./__mocks__/SomeService.js


export const mockGetObjects = jest.fn()


const mock = jest.fn(() => {

    return {getObjects: mockGetObjects}

})


export default mock

然后普通jest.mock('./SomeService')調用與稍后在測試中定義的實現一起工作:


mockGetObjects.mockImplementationOnce(() => {

  return Promise.resolve(object_data).then(response => response.data)

})


查看完整回答
反對 回復 2022-12-22
  • 3 回答
  • 0 關注
  • 154 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號