🧪

写経や情報共有に単体テストを役立てる

2024/12/22に公開

この記事は、ソフトウェアテストの小ネタ Advent Calendar 2024 22日目の記事です

https://qiita.com/advent-calendar/2024/software-testing-koneta

背景

ソフトウェアを開発する際に自動テスト(単体テスト)をちゃんと書こうという価値観は、以前よりもより一般化してきたように感じます
t-wadaさんによるスライドをみたことがある方も多いのでないでしょうか

https://speakerdeck.com/twada/building-automated-test-culture-2024-winter-edition

前述の資料の中で、自動テストは ソフトウェアが変更容易性の高い状態を維持する 目的で作成すべきとあります
業務でシステムを開発していると日々機能開発やバグ修正をおこなうことになるため、的確な指摘と思います

それでは、個人開発や趣味のプログラミングなど、変更容易性やアジリティが求められない状況において自動テストが不要かといえば、全くそんなことはないと私は考えています

今回は、趣味で行っているプログラミングにおいて自動テストが役立ったな〜と思った場面について書き残したいと思います
参考になる部分があれば幸いです🐣

自動テストが役立つ場面

技術記事の写経

本業はWebアプリケーションを開発している企業でSREをしているのですが、SQLのロックタイムアウトが頻発するようになり、調査することがありました

https://zenn.dev/link/comments/c4b98d73378afd

幸いにして原因が無事判明しコードを修正して事なきを得たのですが、 RDBのレコードロックについてなにも知らないな〜 ということに気付いたので、勉強することにしました

MySQLにしろPostgreSQLにしろ、長く運用されているOSSは知見も豊富で、参考になる技術記事や書籍がたくさん発表されています
それらを読むと、例えば以下のような記述が出てきます

https://blog.tiqwab.com/2018/06/10/innodb-locking.html

# 2つのトランザクションTA, TBで以下の操作を行います…
TA> begin;

# TB がレコード更新
TB> begin;
Query OK, 0 rows affected (0.00 sec)

TB> UPDATE lock_sample SET val1 = 3 WHERE id = 2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

TB> commit;
Query OK, 0 rows affected (0.01 sec)

# TA がトランザクション初 read。
# スナップショットはトランザクション開始時ではなくこのタイミングに基づく。
# なので TB で commit したものが読める。
TA> SELECT * FROM lock_sample;
+----+------+
| id | val1 |
+----+------+
|  1 |    1 |
|  2 |    3 |
|  3 |   10 |
|  4 |   10 |
|  5 |    4 |
|  6 |   10 |
+----+------+
6 rows in set (0.00 sec)

(後略)

DockerなどでMySQLを立ち上げて実際に挙動を確かめてみると確かにそのようになるのですが、読み続けているとだんだん確認が面倒になっていき、部分的に飛ばしてしまったり、目視を誤ってそもそも正しく状態を確認できていなかった…ということがありました

これについて、技術記事や書籍の内容を写経する際に、Pythonのunittestを用いて自動テストとして再現すると、再現性があり検証観点もはっきりと残すようにできるのでないかと思いました

試してみたのが、以下のリポジトリになります

https://github.com/yktakaha4/rdb-lock-newbie

例えば、先ほどの記事の内容の単体テストは以下のようになりました

https://github.com/yktakaha4/rdb-lock-newbie/blob/7d2c9778b81fed035b9393535979c3093c656fac/test_mysql_lock_tiqwablog.py#L63-L91

メリットとして以下がありました

  • テスト対象を観察する時間が増える
    • 単純なコピペが難しいので書いてあることをよく読む
    • どの部分をアサーションすればflakyでないテストケースにできるか考える
  • 言語への理解も深まる
    • 書いてあることと同じ状況をプログラミング言語で再現するにはどうすればよいか、調べる必要がある
    • 今回だと複数トランザクションを平行に呼び出す必要があったため、マルチスレッドの勉強も追加で必要になった
  • 他人に共有できる
    • うまく実装できない部分について同僚にリポジトリを投げたところ、修正PRを出してくれた

デメリットとしては、テストに用いた言語に習熟していないと余分な時間がかかるところがありますが、生成AIなども活用しつつ学習できると良いものと思います🧠

コードスニペットの共有

私はISUCONというWebアプリのパフォーマンスチューニングを行うコンテストにGo言語で参加しています

https://isucon.net/

毎年3人チームで挑んでいるのですが、皆本業でGoを書いているわけではないので、役立ちそうなコード片をあらかじめ用意しておき、当日の問題に合わせてコピペして使うという手法で挑んでいます

コードは以下になります

https://github.com/isushintaro/isunippets

例えば、DBから取得したレコードをMapに詰め替えるというスニペットを作ったとします

https://github.com/isushintaro/isunippets/blob/6e2ffca0314d148ef3780076ed1e8cc145cf0b70/collection.go#L3-L10

それに対して、セットで以下のように単体テストを作っておきます

https://github.com/isushintaro/isunippets/blob/6e2ffca0314d148ef3780076ed1e8cc145cf0b70/collection_test.go#L8-L29

メリットは以下です

  • 他のメンバーにも使ってもらいやすい
    • 本番中に修正箇所を検討する際に、 このリポジトリのこのコードを使って直すといい みたいなコミュニケーションができるため、会話だけでイメージを伝えるよりもお互い楽
    • テストコードを読めばスニペットの使い方もわかる
  • 長く使える
    • ISUCONで提供される初期実装の言語バージョンは毎回新しいものに更新されるが、新しいGoでも動くことを簡単に確認できる

いずれのケースも、アジリティや変更容易性の向上を目的としたテストではありませんが、一定のメリットがあるのでないかと思います
自動テストを使ってエンジニアライフをより良くできるよう、引き続き活用方法を検討していきたいです🐥

Discussion