若手プログラマーがテストを学んだ過程


テストについて学習できる心の余裕ができたので、自分が学習した過程を残します。

自分の技術感

・Swift 5年(5年ほどの強さはない)
・Dart(Flutter) 1年
・C# 1年半
・JavaScript 1年
・PHP/Ruby 読める
・HTML/CSS 読める

実務経験
・3年弱くらい

学ぼうと思った背景

技術的側面

実務でテストコードを書いているが、

・なぜテストコードを書かなければいけないのか?
・どこに対してテストコードを書くべきなのか?

がわからなかった。

気持ち的な面

個人開発などでテストコードを書いてこなかったので、そこに対する劣等感が大きかった。
「テストコードをあまり書いていない」というと大抵の中堅のエンジニアさんには
「ダメだな」と言われていたので、ここらでステップアップが必要だと感じた。

加えて「テストに対する意識が高い若手エンジニアが少ない」と感じたので
書けるようになったら差をつけられるかなと感じた。

そして心理的に少し余裕ができてきたので学習してみる。

なぜテストコードを書くのか?

まずなぜテストコードを書かなければいけないのか調べてたり、読んでみた。

読んでみた記事

テスト系の記事を読むとカバレッジという言葉がよく出てきたので、
意味を調べてみた
カバレッジ

テスト系記事
テストコードの目的と意味

希薄化したTDD、プロダクトの成長のために必要なものは?〜『健全なビジネスの継続的成長のためには健全なコードが必要だ』対談 (6)

【初心者向け】テストコードの方針を考える(何をテストすべきか?どんなテストを書くべきか?)

スピード感重視なのでテストは書かない。テストはなぜ開発を遅くするか

テストコードとか書いてみてもいいんじゃない?

読んでみた結果

読んでみた結果、自分が「タシカニ」と感じた部分を列挙すると

・手作業で何度もテストするより、自動化した方が明らかに速いところ部分がある
→アカウント作成時の確認メール送信・バリデーションチェックなど手作業で確認するよりコードのが絶対早い

・リファクタリング時(orライブラリのアップデート時)に品質を担保できる
→テストがパスされれば大丈夫という風にテストコードを書いておけば、リファクタリングしてもテストがパスされれば、ある程度は大丈夫ということが担保できる

・テストファーストで考えれば、テストを前提としないコードを書く意味がない
→自分のイメージだとそもそも「テストと実装は別」と考えてしまっていたので、最初からテストありきで実装すれば別に実装コストは変わらない(テストコードを書くのに慣れる必要はあるが)

所感

読めば読むほど、自分が今までテストコードに実装してことが愚かなことなのだと実感するとともに
自分と同じように「なぜテストコードを書かなければいけないのか」がよくわからない人も多くいるのだと実感した。

個人開発でもテストコードをしっかり書いてるエンジニアが、よく中堅エンジニアの方に「いいエンジニアだ」と言われるのも、これだけテストに対する意識が低い人が多いなら納得だなと感じた(同時に反省)

どこに対してテストコードを書くべきなのか?

なぜテストコードを書かなければいけないのかがわかったので、
今度はどんなテストコードを書かなければいけないのか、調べてみた。

読んでみた記事

↓上記にあるやつと同じ
【初心者向け】テストコードの方針を考える(何をテストすべきか?どんなテストを書くべきか?)

読んでみた結果

上記の記事より引用

セキュリティ上、重要なところ
・権限管理など
不具合があると致命的なところ
・課金や決済など、お金を扱うところ
・メールの送信先
そのシステムの重要度の高いユースケース
ネット販売サービスであれば、「ユーザー登録して、商品を選択して、購入」という一連の流れがそれに該当する
例外処理
例外処理系、普通は通らない部分はMockを作成してわざと通るようにする

とりあえずシステムとして重要な部分(曖昧な理解)には必要なんだね

所感

なるほどとはなるが、
具体的に「自分が作るシステム」だったらどこに必要なんだろうというのがまだイメージができない。

自分は個人開発だとFirebaseを使用して、

・閉鎖的なSNSのような投稿系のアプリ
・TODOのような管理系のアプリ

を作成することが多いので、その辺りをベースにどのようなテストコードを書くべきなのか
まずは考えてみることにする。

閉鎖的なSNSをベースにどのようなテストを書くべきか考えてみる

閉鎖的なSNSの仕様

※めちゃめちゃ簡易的な機能にしています。

通信が必要な機能

  • ログイン/新規登録
  • 友人登録機能
  • 投稿機能
  • TL機能

詳細の機能

ログイン/新規登録

  • バリデーションチェック
  • 通信時のエラー
    • 通信できない
    • ユーザーが存在しない場合(ログイン時のみ)
    • 既にユーザーが存在する場合(新規登録時のみ)

友人登録機能

  • ユーザーの検索IDで検索
  • 通信時のエラー
    • 通信できない
    • 友人登録済みの場合はユーザーは表示しない

投稿機能

  • バリデーションチェック
  • 通信時のエラー
    • 通信できない
  • 投稿をトリガーにcloudFunctionsでuserのTimeLineに書き込み

TL機能

  • 友人の投稿のみ表示

Firestoreのテーブル構造

今回簡単のため、この辺りは重きを置いてないです。

Users
  └uid
    └field(ユーザー情報)
    └friend(userのuidの配列)
    └TimeLine(SubCollection)
        └ uid(postの)
            └ field(投稿内容)

Posts
  └uid
    └field(投稿内容)
    └投稿者のuid

テストが必要な部分

・バリデーションチェック
→テストコードを書いて全パターン通るようにする。

・Firestoreへの更新周り
→Firestore更新時に更新するFieldが正しいか確認する

・CloudFunctionsでコピー時のテスト
→なくても良さそうですが・・。
https://medium.com/google-cloud-jp/firestore4-28f1fb44a1e8

・実装でトリッキーになりそうなコード
→ここは実際に実装してみないとわからなそう・・

パッと思いついたのはこのあたりですが、
ぜんぜんまだある気もします。

軽く調べてみて

テストファースト的な考え方は調べるまで全く意識できていなかったので、
そこはいろいろ調べてみてよかったです。
テスト駆動開発

次はこちらの参考書を一読後
実際にテストコードを書いていこうと思います。