[GraphQL] Apollo Client를 사용하는 React 컴포넌트 테스트하기 (MockedProvider)
Apollo Client를 사용하여 GraphQL API를 호출하는 React 컴포넌트를 테스트하는 방법에 대해서 알아보겠습니다.
예제 컴포넌트 작성
Apollo Client를 사용하여 GraphQL API를 호출하는 매우 간단한 React 컴포넌트를 작성해보겠습니다.
아래 PingPong
컴포넌트는 GraphQL 서버에 ping
이라는 쿼리를 호출합니다.
서버로부터 응답이 올 때까지는 Loading...
라는 메시지를 렌더링합니다.
만약에, 서버로 부터 에러가 응답되면 Error!
라는 메시지를 렌더링합니다.
마지막으로 서버로 부터 정상적으로 데이터가 응답되면, 해당 데이터를 렌더링합니다.
import React from "react";
import { gql } from "apollo-boost";
import { Query } from "react-apollo";
export const PING_QUERY = gql`
query ping {
ping
}
`;
function PingPong() {
return (
<Query query={PING_QUERY}>
{({ loading, error, data }) => {
if (loading) return <p>Loading...</p>;
if (error) return <p>Error!</p>;
return <p>{data.ping}</p>;
}}
</Query>
);
}
export default PingPong;
기존에 Apollo Client로 React 컴포넌트를 작성해본 적이 없으신 분들은 위 코드가 이해가 어려울 수도 있습니다. 아래 포스팅에서 Apollo Client를 이용해서 React 앱 개발하는 방법에 대해서 설명하고 있으니 참고 바랍니다.
MockedProvider
Apollo Client를 사용하고 있는 React 컴포넌트에 대한 단위 테스트틀 작성할 때 가장 까다로운 부분이 실제로 GraphQL 서버와 연동이 필요하다는 점입니다.
상용 코드에서 사용하는 ApolloProvider
는 client
prop에 ApolloClient
객체를 넘겨달라고 요구하는데, ApolloClient
객체를 생성할 때는 연동할 GraphQL 서버의 접속 정보를 설정해줘야 합니다.
이는 “단위 테스트는 다른 모듈에 의존하지 않고 격리되어 실행될 수 있어야 한다”는 기본 원칙에 위배되며, 실제로 단위 테스트 용 GraphQL 서버를 갖출 수 있다고 해도 테스트 실행 속도가 매우 느려질 것입니다.
import ApolloClient from "apollo-boost";
import { ApolloProvider } from "react-apollo";
const client = new ApolloClient({
uri: "https://www.my-graphql-server.com",
});
<ApolloProvider client={client}>
<MyComponent />
</ApolloProvider>;
해결 방법은 ApolloProvider
를 모킹(mocking)하여 실제로 GraphQL 서버와 연동하는 것처럼 React 컴포넌트를 속여주는 것입니다.
이를 위해, Apollo Client의 React 용 라이브러리인 react-apollo
는 MockedProvider
를 제공해주고 있습니다.
MockedProvider
는 ApolloClient
객체를 필요로 하는 ApolloProvider
와 달리 단지 가짜 데이터만을 필요로 합니다.
import { MockedProvider } from "react-apollo/test-utils";
const mocks = [
{
request: {
query: ...,
variables: { ... },
},
result: {
data: { ... },
},
},
];
<MockedProvider mocks={mocks} addTypename={false}>
<MyComponent />
</MockedProvider>
각 요청에 대한 가짜 응답 결과를 담고 있는 mocks
배열을 MockedProvider
에 넘겨주면 실제 GraphQL 서버가 없이도 MyComponent
를 테스트할 수가 있습니다.
단위 테스트 작성
React 테스트를 작성할 때는 많이 사용되는 Jest와 React Testing Library를 이용해서 예제 컴포넌트에 대한 테스트를 작성해보겠습니다.
Jest와 React Testing Library에 대한 기본적인 설명은 다음 포스팅를 참고 바랍니다.
먼저 서버로부터 응답이 올 때까지는 Loading...
라는 메시지를 제대로 렌더링이 되는지 체크해보겠습니다.
import React from "react";
import { MockedProvider } from "react-apollo/test-utils";
import { render, wait } from "@testing-library/react";
import PingPong, { PING_QUERY } from "./PingPong";
test("<PingPong/> renders loading while fetching data", () => {
const { getByText } = render(
<MockedProvider>
<PingPong />
</MockedProvider>
);
expect(getByText("Loading...")).toBeInTheDocument();
});
React Testing Library의 render()
함수를 이용해서 테스트할 PingPong
컴포넌트를 DOM에 렌더링해야합니다.
이 때, 위에서 설명드린 MockedProvider
컴포넌트로 PingPong
컴포넌트를 감싸줘야 합니다.
그 다음, React Testing Library의 getByText()
함수로 Loading...
메시지를 포함하고 있는 컴포넌트를 선택합니다.
마지막으로 jest-dom
의 매처 함수인 toBeInTheDocument()
를 이용해서 선택한 컴포넌트가 DOM 안에 존재하고 있는지 검증합니다.
다음으로 서버로 부터 에러가 응답되면 Error!
라는 메시지가 제대로 렌더링이 되는지 체크해보겠습니다.
test("<PingPong/> renders error when error is responded", async () => {
const { getByText } = render(
<MockedProvider>
<PingPong />
</MockedProvider>
);
await wait(() => expect(getByText("Error!")).toBeInTheDocument());
});
MockedProvider
는 mocks
prop을 넘기지 않은 경우에는 항상 가짜 에러를 응답해줍니다.
여기서 중요한 것은, 화면에서 Error!
메시지가 나타날 때까지 기다려야 한다는 점입니다.
React Testing Library의 wait()
함수와 JavaScript의 async/await
키워드를 사용하여 비동기 처리를 해줍니다.
마지막으로 서버로 부터 정상적으로 데이터가 응답되면, 해당 데이터가 렌더링되는지를 체크해보겠습니다.
test("<PingPong/> renders data when data is responded", async () => {
const mocks = [
{
request: {
query: PING_QUERY,
},
result: {
data: { ping: "pong" },
},
},
];
const { getByText } = render(
<MockedProvider mocks={mocks} addTypename={false}>
<PingPong />
</MockedProvider>
);
await wait(() => expect(getByText("pong")).toBeInTheDocument());
});
이 번에는 PingPong
컴포넌트가 가짜 응답을 받아야 하기 때문에, MockedProvider
컴포넌트의 mocks
prop에 ping
쿼리에 대한 가짜 응답을 담고 있는 배열을 넘겨줍니다.
대게의 경우 addTypename
prop은 false
로 세팅하는데, true
세팅해줄 경우, 요청 정보가 __typename
필드까지 포함해야 하기 때문입니다.
마치면서
지금까지 Apollo Client를 사용하여 GraphQL API를 호출하는 React 컴포넌트를 테스트하는 방법에 대해서 알아보겠습니다. 예제 프로젝트의 전체 코드는 아래를 통해 확인하실 수 있습니다.