ReactのBDD勉強としてサービス作ってみた


TL;DR

  • フロントエンドBDDの勉強用に、簡単なサービス作った。
  • テスト書くの良い。
  • サービス公開とか色々本筋でないとこに結構引っかかった。
  • Javascript難しい。
  • フロントエンド難しい。

What's this?

最近業務でswiftを触っていたのもあり、勉強の方向性がフロントエンドに偏りつつある。
Reactは以前から学習に取り組み、簡易な実装経験があったが、
そもそも機能を実現することも重要だが、システムとして長期運用していく上で重要になるテストコードについても勉強したいと思ったので、じゃあReactでテスト書きつつシステム一個作って見よう!という試みで開始した。

作ったもの

サービス:https://timer-d73c3.web.app
GitHub:https://github.com/theMistletoe/RecoSta

起動中の経過時間を計測してるサービス。勉強時間・作業時間を記録することが目的。
エンジニアたるもの20h/weekは勉強するのは最低ラインとのことで、
私はどのくらいできているかな〜というのが気になった、ところから作ってみました。

使用したテストライブラリ

react-testing-libraryというライブラリで、Reactに置ける振る舞い駆動テストを実現するためのライブラリを使った。
swiftでもBDDをしていたこともあり、今後の潮流的にもBDD来てそうだなと思ったので使ってみた。
参考で詳しく書いてくださってる記事を載せています。

実際に書いてたテストコードが下記

describe("Main Page",  () => {

        it("get and display studytimes", async () => {
            const spy = jest.spyOn(axios, 'get').mockImplementation(() => {
                return {
                    data: [{date: '20191121', studytime: '2315'}, {date: '20320408', studytime: '444'}]
                }
            });

            const { getByText, getAllByTestId, getByPlaceholderText } = await render(<Main />);

            await waitForElement(() => getAllByTestId("studytime-list"));

            expect(firebase.auth().currentUser.getIdToken).toHaveBeenCalled();
            expect(spy).toHaveBeenCalledWith(`${process.env.REACT_APP_BACKEND_ENDPOINT}/api/v1/studytime`, 
            {headers: { authorization: `Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` }});

            expect(getByText("Total: You've studieds 2759 seconds!")).toBeInTheDocument();
            expect(getByPlaceholderText("Input Your Email Address")).toBeInTheDocument();

            expect(getByText("Now, You've studied")).toBeInTheDocument();
            expect(getByText("Date")).toBeInTheDocument();
            expect(getByText("Studied Times(s)")).toBeInTheDocument();
            expect(getByText("20191121")).toBeInTheDocument();
            expect(getByText("2315")).toBeInTheDocument();
            expect(getByText("20320408")).toBeInTheDocument();
            expect(getByText("444")).toBeInTheDocument();
        });
}

BDDっぽいところでいうと、
expect(getByText("20191121")).toBeInTheDocument();
みたいにHTMLの画面上に想定通りの文字や入力欄が存在するかどうかをテストコードで表現できる。
こうすることで、ユーザーからみた挙動に近い形で、テストコードをSpecとして表現できる。

システム構成

構成自体はJAMStack?のはず?です。

Firebaseを中心に活用しつつ、バックエンドだけHeroku使ってる感じです。
Firebase HostingにReactのフロントエンドをデプロイしています。
バックエンドもNode.js(express)でさっくり書いています。

データストアはFireStoreというFirebaseのNoSQLを使用しています。エンティティ設計がちとめんどくさいですが、簡単なサービスを作るときには簡単にできて良い感じですね。

認証にもFirebase Authenticationを使用していて、メールアドレスによる認証を行なっています。
この辺の認証周りとかすごいめんどくさかった、、自分が理解できていないこともあるが、、、

そもそもFirebaseのmBaasの考え方的にバックエンドを挟む構成がいまいち向いていない感じがありますね。初めはバックエンド書かずにやろうとしたんですが、axiosのHTTPリクエストのテストがしたかったのと、よくわからなかったので逃げてしまった、、、

まとめ

テスト・BDDの勉強のためにサービス作りながら実際に適用できそうか勉強しながらやってみて、
BDD・TDDを実践しながら作ると、個人開発であっても実装に迷うことが少なくなり、方向性を見失うことはなかったように思う。
が、ここで早くなったと書かなかったのは、テストの書き方とか、Jestわからんとか、Mock効かねぇとか、テスト周りで実装に詰まることが格段に増え、すっごい時間がかかってしまった。

そもそもJavascriptへの理解が全然追いついていないとひしひしと感じた。バックエンドで使ってるような言語のスタンスで取り組むと、全然期待する挙動にならずオワタ...になる。

一旦ベースができたので、 実はテスト書けてないところとか、設計オワコンなところとか、 改善点を直しながら理解を深める活動ができればいいな、と思っている。

参考