[エレガントな技術ルート#6]ネットワーク通信のテスト
ネットワーク通信をテストします
今回のYouTubeタスクは以下の通りです.
YouTube検索APIを使用して応答データを私のアプリケーションに送信する必要があります.そのため、ネットワーク通信のためのコードを実装する必要があります.次のコードは、ネットワーク要求を実行するモジュールです.
グリップモジュールコード
// fetcher.js
import { createUrl } from '../utils/util';
const generateFetcher =
(API_URL) =>
async ({ path, params }) => {
const url = createUrl(API_URL, path, params);
/* 실제 응답을 받아냅니다 */
const response = await fetch(url, { method: 'GET' });
/** 빠른 실패 */
if (!response.ok) {
throw new Error(`api 요청 중 에러 발생: ${response.status}`);
}
const data = await response.json();
return data;
};
export const youtubeAPIFetcher = generateFetcher('https://jolly-agnesi-fe3944.netlify.app');
generateFetcher
:fetcher
モジュールのフック関数.作成してfetcher
モジュールに戻り、API URLをパラメータとして受け入れ、API URLのEND POINTのみに要求を送信する.// 사용처
async requestVideoById(id) {
const videoResult = await youtubeAPIFetcher({
// path는 엔드포인트를 말합니다.
path: API_PATHS.GET_VIDEO,
// 요청에 넣을 쿼리 값
params: {
id,
part: 'snippet',
},
});
const {
items: [videoInfos],
} = parserVideos(videoResult);
return Video.create({ ...videoInfos, videoId: id });
}
これらのコードをテストしてみましょう.
ネットワーク通信のテスト
YouTube APIでは、毎日のリクエスト数が限られているため、直接リクエストを送信するのではなく、mocking
をデータを返す関数として使用してみます.
Jestテストを使用してモジュールユニットをキャプチャする
node
環境で動作するjest
の場合、fetch
関数は存在しないため、いくつかの動作が必要である.global
グローバルオブジェクトを変更する方法を多くの方法で選択しました.
他に選択肢はない
// fetcher.js
import { createUrl } from '../utils/util';
const generateFetcher =
(API_URL) =>
async ({ path, params }) => {
const url = createUrl(API_URL, path, params);
/* 실제 응답을 받아냅니다 */
const response = await fetch(url, { method: 'GET' });
/** 빠른 실패 */
if (!response.ok) {
throw new Error(`api 요청 중 에러 발생: ${response.status}`);
}
const data = await response.json();
return data;
};
export const youtubeAPIFetcher = generateFetcher('https://jolly-agnesi-fe3944.netlify.app');
// 사용처
async requestVideoById(id) {
const videoResult = await youtubeAPIFetcher({
// path는 엔드포인트를 말합니다.
path: API_PATHS.GET_VIDEO,
// 요청에 넣을 쿼리 값
params: {
id,
part: 'snippet',
},
});
const {
items: [videoInfos],
} = parserVideos(videoResult);
return Video.create({ ...videoInfos, videoId: id });
}
リクエストを直接送信しません.
global
グローバルオブジェクトにfetch
という名前のメソッドを追加することによって、クライアントモジュールでfetch
を呼び出すときにこの関数を呼び出すことが実現される.fetch
と同じ条件を達成するために,Promise
を用いて非同期を実現した.describe('fetcher 모듈 테스트', () => {
global.API_URL = 'https://jolly-agnesi-fe3944.netlify.app';
test('비디오 데이터를 응답한다', async () => {
// mocking - client 단에서 사용되는 fetch 함수가 아닙니다. 이 함수는 mocking 된 함수이며, dummyVideo data를 포함한 가짜 응답 리소스를 반환하는 함수입니다.
global.fetch = jest.fn(() =>
Promise.resolve({ ok: true, json: () => Promise.resolve(dummyVideo) })
);
// youtubeAPIFetcher 내에서 fetch 함수를 호출하여도, node 전역 객체(global)에 있는 fetch 함수가 호출되게 된다.
const video = await youtubeAPIFetcher({
path: API_PATHS.SEARCH,
parmas: {
q: 'keyword',
part: 'snippet',
maxResults: 10,
type: 'video',
pageToken: '',
},
});
expect(video).toEqual(dummyVideo);
});
test('잘못된 요청의 경우 에러를 throw한다', () => {
// mocking - client 단에서 사용되는 fetch 함수가 아닙니다. 이 함수는 mocking 된 함수이며, dummyVideo data를 포함한 가짜 응답 리소스를 반환하는 함수입니다.
global.fetch = jest.fn(() =>
Promise.resolve({ ok: false, json: () => Promise.resolve(dummyVideo) })
);
expect(
// youtubeAPIFetcher 내에서 fetch 함수를 호출하여도, node 전역 객체(global)에 있는 fetch 함수가 호출되게 된다.
youtubeAPIFetcher({
path: API_PATHS.SEARCH,
parmas: {
q: 'keyword',
part: 'snippet',
maxResults: 10,
type: 'video',
pageToken: '',
},
})
).rejects.toThrow();
});
});
私が作成したモジュールをテストするという意味であれば、そうすることができます.しかし、Unit TestでAPI fetching
をテストする必要はありますか?処理ドメインの他の論理のテストに集中すべきではないでしょうか.(API Fetching
に対するテストはE2E Test
に延期された)Reference
jest - async testing
jest - using node-fetch in test
CypressによるE 2 Eテスト
Jest
がfetcher
モジュールのユニットテストを行った場合、E 2 EテストはAPI応答データが画面によく表示されるかどうかをテストする必要があります.アイデア
jest
と同様に、割り当てられたAPI鍵を使用する要求数をテストしたくない.そこで、以下のアイデアに基づいて開発を行いました.私は本当の要求を出さない.
API Request
を横棒としてmock Data
を返します.1.
fixture
データ(実際のリクエストの応答と同じ)mock
+ custom command
// cypress/support/command.js
Cypress.Commands.add('interceptAPIRequest', (PATH) => {
const API_URL = 'https://jolly-agnesi-fe3944.netlify.app';
if (PATH === API_PATHS.SEARCH) {
// 첫번째 인자로 가는 요청을 인터셉트하여 두번째 인자에 설정되어 있는 `fixture` 데이터를 반환한다.
return cy.intercept(`${API_URL}/${PATH}*`, { fixture: 'searchResult' }).as(PATH);
}
if (PATH === API_PATHS.GET_VIDEO) {
return cy.intercept(`${API_URL}/${PATH}*`, { fixture: 'video' }).as(PATH);
}
});
// cypress/integration/search.test.js
describe('사용자는 검색을 통해 영상을 확인할 수 있다.', () => {
const baseURL = 'http://localhost:9000/';
beforeEach(() => {
cy.visit(baseURL);
cy.showModal();
});
it('모달 버튼을 클릭 후, 검색어를 입력하면 결과를 확인할 수 있다.', () => {
const validKeyword = '정상검색';
// API_URL + API_PATH(END_POINT)으로 가는 요청을 intercept하는 커스텀 커맨드 입니다.
cy.interceptAPIRequest(API_PATHS.SEARCH);
cy.get('#search-input-keyword').type(validKeyword);
cy.get('#search-button').click();
cy.get('.video-item').should('exist');
});
});
ReferenceReference
この問題について([エレガントな技術ルート#6]ネットワーク通信のテスト), 我々は、より多くの情報をここで見つけました https://velog.io/@rat8397/우아한테크코스-6-네트워크-통신-테스트テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol