Upgrade to Pro — share decks privately, control downloads, hide ads and more …

スタートアップだからこそ考えるフロントエンドのテスト戦略

 スタートアップだからこそ考えるフロントエンドのテスト戦略

2023-03-21-saitama.js

Ibuki Yoshinaga

March 21, 2023
Tweet

More Decks by Ibuki Yoshinaga

Other Decks in Technology

Transcript

  1. 所属している会社 Misson e スポーツで 一人ひとりの可能性が ひろがる教育機会を e スポーツとは 「e スポーツ」とは、「エレクトロニック・スポーツ(Electronic

    Sports )」の略で、ビデオゲームを使った対戦をスポーツ競技として 捉える際の名称を指す。 つい数年前まではオタクの趣味または「ゲームは悪」と捉えられてい たが、現在では海外での人気のみならず、日本においてもさいたまス ーパーアリーナを埋め尽くすほどの観客動員数を誇り始めている。 ゲシピ株式会社
  2. 最近開発しているサービス 主力サービスをさらに発展させるため、9 月より1 人目の正社員エンジニアとして僕がジョインしました。 実は弊社に関わり始めたのは高校生の頃なので、超待望のリリースって感じです。 概要 主に小学生~ 大人向けの英会話レッスンを提供するtoC サービ ス

    特徴 ネイティブスピーカーの講師陣とFortnite やマイクラを遊びな がら、英会話を教えてもらえる。 ゲーム内でのやり取りは基本全て英語、ゲームを用いたカリ キュラムが組まれているため子供達が自主的に取り組みやす く英語に対する苦手意識も克服できる。 ニュース 最近リスキリングe スポーツ英会話がリリース🎉大人向けの 英会話レッスンがゲームを通した会話で学べます。 e スポーツ英会話
  3. 開発初期に採用した主な技術 ・Next.js + TypeScript ・react-hook-form ・Recoil フロントエンド ・Nest.js + TypeScript

    ・Prisma ・OpenApi ・PostgreSQL バックエンド ・Heroku ・Docker インフラ ・GitHub Actions CI/CD
  4. 現在の開発体制 会社全体で正社員 10 人未満のスタートアップ 現在の開発組織 (2022/09~) CTO( 設計 + 他プロダクト

    + マネージメント) ワイ( 設計 + 開発) フルタイム 業務委託( 設計 + 開発) 業務委託( 設計 + 開発) 業務委託( デザイナー) その他 ・全体的に若い組織、CTO 以外の開発者は全員20 代 ・全プロダクトでTS を採用している ・新規開発が多いフェーズ ・正社員で開発に関わるエンジニアは自分だけ ・よほど大きなものでない限りはフロントエンド・バックエンドは一人でやる ・テストを書いた経験は全員少ない 開発組織の特徴
  5. Testing Trophy によれば 上にいけば行くほど実装コストが高くなるが信頼性が上がる。体積 が大きいほど重点が置かれている。 各項目の説明 実際の環境でアプリケーションを動かすテスト End to End

    関数(hooks) やコンポーネントを組み合わせた時のテスト ここを一番厚く書くことが推奨される Integration atoms レベルのコンポーネントや、関数(hooks) 単体のテスト Unit 静的テスト、lint とか Static
  6. React Testing Library ・コンポーネント・カスタムフックのテスト ・Storybook との連携 ・1hooks 、component 毎にテストが作られる ・PR

    内のCI で怒られたい 期待した役割 ・ロジックに関わる部分は基本的にRTL に集約 ・期待通りの結果が表示・返却されているかの確認だけで、スタイルの崩れなどはここでは見ない ・ビジネスロジックに関わらなそうな部分のテストコード作成は、たまにChatGPT に投げている 現状の運用方法 ・結合テストの充実 ・MSW を入れたい( 現在はAPI を使う場合型と同じ形の値をmock してしまっている) 今後の期待
  7. 実装例 1 口座の情報をprops から受け取って、それが整形されて返ってくるhooks のテスト describe(__dirname, () => { it('should

    return the correct text for a domestic bank transfer', async () => { const bankAccount: any = { transfer_method: 'domestic', bank_name: 'Test Bank', branch_name: 'Test Branch', account_type: 'checking', account_number: '123456789', account_holder_name: 'Test User', }; const { result } = renderHook(() => useRemittanceText({ bankAccount })); await waitFor(() => { expect(result.current.get).toEqual({ section1: 'Test Bank Test Branch', section2: ' 当座 123456789  Test User', }); }); }); });
  8. 実装例 2 コンポーネントのテスト with Storybook 余談: 最近play という関数を知った。フォームコンポーネントなどの結合テストを書く場合、RTL 主導にするよりもStorybook 内でテ

    ストを書いて、それをRTL で結果を見て判断する方法に変えていくのもありだなと思った。 const { $Example } = composeStories(stories); describe(__dirname, () => { test(`${CLASS_SCHEDULE_STATUS.COMPLETED} の時${CLASS_SCHEDULE_STATUS_TEXT.completed} が表示される`, () => { const { getByText } = render( $Example lessonStatus={CLASS_SCHEDULE_STATUS.COMPLETED} > ); expect(getByText(CLASS_SCHEDULE_STATUS_TEXT.completed)).toBeInTheDocument(); }); test(`${CLASS_SCHEDULE_STATUS.IMPLEMENTATION} の時${CLASS_SCHEDULE_STATUS_TEXT.implementation} が表示される`, () => { const { getByText } = render( $Example lessonStatus={CLASS_SCHEDULE_STATUS.IMPLEMENTATION} > ); expect( getByText(CLASS_SCHEDULE_STATUS_TEXT.implementation) ).toBeInTheDocument(); }); });
  9. Storybook ・ Chromatic ・Storybook 駆動開発がしたい( 願望) ・コンポーネント毎のカタログが欲しい ・1 コンポーネントにつき1 つのstory

    ファイルが作られる ・スナップショットテストやビジュアルリグレッションテスト 期待した役割 ・atom レベルのコンポーネントは必ずstory ファイルを作成する ・スタイル崩れなどはここで検知する 現状の運用方法 ・Chromatic に代わる何かを導入する( 後述) ・play などを使って、結合テストをより充実させる 今後の期待
  10. 実装例 アイコンを表示するコンポーネント type Component = typeof BaseIcon; type Meta =

    ComponentMeta<Component>; export default { title: 'frontend/src/components/common/FixSb/BaseIcon', component: BaseIcon, argTypes: { icon: { options: Object.keys(ICONS), control: { type: 'radio' }, defaultValue: 'lined_reward', }, }, } as Meta; const Template: Story<BaseIconProps> = (args) => <BaseIcon {...args} >; export const $Example = Template.bind({}); $Example.args = { icon: 'lined_reward', };
  11. テストを導入してどうだったか・まとめ 現在はノルマ・目標などは設けておらず、atom レベルのロジックを持ったコンポーネントにはStorybook 、新しく発行したカスタム フックにはテストを書いてねくらいのゆるさにしている。 現在弊社ではある一定の期間でリファクタウィークを設けて、そこでテストを含めた負債の解消をしようとしています。 すぐに全てのテストを作れはしない ( モチベ的にも )

    ので、継続して対応することが必要。 ・デグレによる不安が少し解消された ・古くからある機能や壊れやすい部分をE2E で担保することで、該当機能を充実させるまでの時間稼ぎができている ・エラーが起こった時に、ある程度規模感を検知・場合によってはrevert できる ・知見が溜まってない頃に書いたコードは普通に汚いので、ある意味強制的なリファクタリングが発生する ・現状一人で開発している僕にとって、ある一定の心理的安全性が保たれる よかった点 ・テストの粒度を決めきれていない、網羅しきれていない ・知見・時間等の理由で明確なシナリオを用意できていないため、正常系が主体になってしまっている ・一時的だがChromatic を消してしまった今、明確にStorybook に登録するメリットを感じきれていない ・デザイナーを正社員として雇っていないこともあり、動機的なStorybook 駆動開発をするにはまだ時間がかかりそう 懸念点・もっと頑張る