This page looks best with JavaScript enabled
⚠️

TDD Boot Camp 2020 Online #1【レポ】

 ·   ·  ☕ 10 分で読めます
✏️

TDD Boot Camp 2020 Onlineに参加しました。
テスト駆動開発は大事だなあと思っていたものの、実際にコードを書くときにはさっさと書いていました。

そんな折にこの機会。しかもペアプロもめっちゃ興味があった。
こんな猛者が集いそうなところに未経験が行くのはどうなんだ?とは思ったものの、逆に言うと伸びしろしかない。
ということで、いったれ!の精神で応募しました。ちなみに人気がえぐくて、数時間で締め切りになっていたと思います。
散漫としていますが、なんとなく取っていたメモを元にレポートを残しておきます。

ペアプロライブコーディング

事前準備の日にペアプロのライブコーディングを見ました。

ドライバーは随時思考を口にしながら実装し、ナビゲーターが指示を出したりコードのサポートする。
流れるように会話をしながら実装していき、しかし相談するところはしっかり相談して、という印象でした。
RED→GREEN→REFACTORで盛り上がるチャット欄が楽しかったです。

また、命名についてかなりいろんな意見が出ていました。
top bottom / upper under / above below
命名で決まらない場合は、あえてなっがい名前にしておくという方法もあるらしい。

コミットメッセージはREDかGREENがわかりやすくする、とのこと(今思うと自分できてなかったなあ)。

ちなみに、基本的に検索はナビゲーターがするらしいというのを聞いて、このとき「えっまじか。空でコード書けるかな」と思っていました。

その後、Rubyチームで集まって環境構築をしながらペアプロの準備をしました。
が、1人欠席になったため、3人でモブプロにすることになりました。

t_wadaさんによる基調講演とライブコーディング

「動作するきれいなコード」が目的。

まずはやることをリストアップ
最初に倒すものを選ぶ(重要度の高いものから・書きやすいものから)
最初のうちのテストは結構重いので軽いものからスタート。

重要・テスト容易性は一致させられる!
重要なもの、テスト容易性の軸で4象限で考える。

利用者の視点でテストを書く。自分が最初のコードの利用者になる。
とりあえずテストを通す!汚さは問題ない!ので、早く書けるはず。

リファクタリング「成功するテストを成功したままでプロダクトコード・テストコードの理解が容易になること」
成功する〜=外部から見たふるまいが同じ の意味。

リファクタリングの辞め時は時間or数で決める。一度で深追いする必要はない。
数……重複をなくす(2or3)


todoリストに戻る

ここまでの過程で出たフィードバックによって設計=todoリストを改定

ライブコーディング

1から100まで、というのは後回しに
→1からnまで

「プリントする」
プリントすること自体、テストできても嬉しくない
viewのテストに似ている。重要ではなくテスト容易性が低い

日本語の記述を対称的にする。
「○の倍数のときは□に変換する(プリントするの要素を置き換える)」
↑これがテスト容易性高、重要度高

「ただし」に着目。
「数を文字列に変換する」

分解の技術

テスト対象の観察のしやすさ・制御のしやすさ・大きさがテスト容易性の基準。
クリーンアーキテクチャでは「入出力からの遠さ」と捉えている。

経験&本などの理論から習得する。


重要度が高いものは、正常系・準正常系っていう風になる。
クラスもディレクトリも何もないので、最初のテストは設計の色合いが強い=勝手に重くなるので、そのときの容易性自体は軽いほうがいい。

テスト対象とテストクラスは今は基本的に一対一。
ファイルは強い単位なので、その中に色々入れればいい。

まず、failメソッドでテストが失敗することを確認する。
「きちんと失敗している」テスティングフレームワークが機能している。ちゃんとテストは動いている!その上で、当然落ちている。

「テストは動く仕様書」だから基本的に日本語の方がいい。

テストメソッドの中は、準備・実行・検証・後片付け
後片付けはコード上ではなかったりする。データベースとかメモリとか?
後片付けを除いて、given, when, thenで分ける。

TDDではassertというゴールからテストを書く。
何をしたいのか目的を明確にしておくこと!

あれ、expectの中身ってなんだ……?何がどうなれば「数を文字列に変換する」ということなんだ?
と、手が止まった瞬間=TODOリストを洗練する瞬間!これに早めに気付ける。

「1を渡すと文字列"1"を返す」という具体的なtodoに変える

「作る前に使う」
使用者側の気持ちを考えること。
コードの作りやすさとコードの使いやすさは違うもの。


さて実践。

まずはコンパイルエラー解消するぞー

1
2
FizzBuzz fizzbuzz = new FizzBuzz
String actual = fizzbuzz.convert(1)

expect 1, actual null

とりあえず通すためにreturn "1"をする。仮実装

仮実装をする理由

これで通らなかったらテストコードが悪いんでしょ?というのが自明
テストコードのテストコードを書いてそのテストコードを……は無限回廊。

ミューテーションツール

実装とテストコードを交互に確認しやすくする

return “0"を入れてREDを確認
テストコードのテストをしたいタイミングはこのタイミングなのでここでしておく。

その後、別の値でもうまくいくかをチェックする。

別の値でもテストが通るか確かめる

2のときに"2"を返すか確かめる。→落ちる。
これを確認することを三角測量という。(絶対これをしないといけないわけではない)

アサーションルーレット

テストが落ちたときにデバッグから始まる。
assertで落ちたところ以下のテストが実行されない。

だからアンチパターン。RSpecでいうと、itの中にexpectは1つにしたい。

テストコードのリファクタリング

2アウト派と3アウト派がいる。
2度は偶然被るということもあるので。

テストコードを読んでもどうあるべきかがわからないのはまずい

「〇〇のとき□を返す」→読む側は「……で?」ってなる。
結局実装コードにしか仕様が書かれてない。具体だけでは仕様がわからない。

解決策

  1. 抽象の言葉__具体の言葉というテスト命名
  2. ツリーにしてネストする

TODOリストの構造と合わせる
レベル感を揃える

テストコードの削除

三角測量の跡が残っていると「2つあるのは意味があるのか?」ってなる。
テストコードの削除は本人にしかできない。
三角測量は実装を終えたら削除してもいい。

テストを書くということはメンテナンスコストがかかることになると心得る。

質問

【質問】複数組み合わさった内容をテストしたいときはそういうテスト用のメソッドを作るべきですかね?
そもそも分解が間違っている?

かなりざっくりした質問になったのですが、いろいろと意見をもらったので残しておきます。


個人的にはテスト用のヘルパーメソッドは作ったりします。名前付けを工夫すれば、かなり可読性も上がると思います。
一方で、そのヘルパーメソッド内で検証している項目が大きすぎる場合は、テスト対象の粒度を再検討する必要があるかもしれませんね


これは大きな機能のレベルをされていますかね?個人的には、「複数」の部分を分解した部分のテストを別途用意します。


こちら、「複数組み合わさった状態」(複雑である、と言えると思います)を「テストしたい」と思うこと自体がTDDをすることによるか貴重なフィードバックだと思っていて、テスト対象の生成が大変な場合はFactoryなど生成自体を責務とするクラスを作ったほうがよい兆候、アサートが大変な場合はそれらの状態をまとめて保持する状態保持クラスみたいなものを作る兆候かなと捉えるようにしています。テスト用メソッドは当然あっていいと思いますがそれが大きく複雑になっては本末転倒なので、プロダクトコード側の設計を検討するほうが健全かと。


まとめてassertしないと意味がないなら一緒にすべき。
getter2つを同時に確認する、戻り値とその副作用を同時に見る。など

でも、まずは疑ってみる。問題が分解できていないのでは??

end to end テストは一度の実行が重いので複数項目をテストしてもok。

カスタムアサーション(RSpecでいうカスタムマッチャ)はドメインの言葉でアサーションを書けるのでよりよい。

モブプロ

一言でいうと「すっごく疲れたけど楽しかった」です。
以下に、反省だったり指摘されたことだったり他の人の意見を聞いてなるほどと思ったことだったり。

他のグループと比較して、TODOリストが少し雑だった。
今回はともかく、もっと複雑になってモックなどを使う場合など、重要度と容易性について熟考しなければならない。

油断するとすぐ大股で歩こうとしてしまう。手綱を握ってきちんと一つ一つ確認しないといけない。
わざとテストを落とす重要性を再確認した。「きちんと失敗する」

小刻みに交代するので、とりあえず後でで棚に上げたのを下ろすのを忘れてしまうことがあった。
→随時TODOに反映させるようにする。

context, describeを、when give then と対応させることを意識したい。

不安をテストする。という感覚を共有することが大事。
どうしてリファクタリングしたの?(それによって何のメリットがあるの?)を語れないとリファクタする意味がない。

ドライバーはぐいぐい引っ張っていきがちになるので、もう少しナビゲーターに委ねたほうがいい。
実際、自分がドライバーをしているときに

「こうした方がいいかな?」というのを言うのが難しかった。とりあえず置いといていいんじゃないかというものとさっさとしておくものの判別がしづらい。
まあでも正直わからないので、区切りのところで言っておいてTODOに入れるのがいいだろうか。

チェリー伊藤さんも前言ってたけど、パラメタライズテストのgem(rspec-parameterized)を入れたほうがコードがわかりやすくなるっぽい。

DRY = ひとつの知識は一箇所に

「コード」ではないので、見かけ上同じでも意味していることが違うならまとめない方がいいという解釈。

感想

コードを書くのを見られているプレッシャーと、一方で困ったら気軽に相談できる気楽さの塩梅がいい。
言葉から処理を想像するまで時間がかかったので、そこを言葉やコードでサポートしてもらえたのが良かった。
最初のどういうクラスを作って処理を入れて……というのが想像つきづらかったので、見ていてくれるのが安心できた。Ruby力!
話にそれなりについていけたのが嬉しかった!

あと、他の言語の人の話やコードを見ていると、RSpecはめちゃくちゃ書きやすいんだなあと思った。
ネストもできるし日本語で直感的なテスト名を付けることもしやすい。ただしletの挙動はかなり独特。

全体の感想

裏側で運営の方がいろいろと組んでいるのがわかっておもしろかった&ためになりました。
怒涛のコメントでライブ感と一体感を感じられたので楽しかったです。わいわいしやすい雰囲気でした。

一方で、いろんな画面を追っていくのが大変でした。ディスプレイ買いたいなあと思いました。
あと、思ったよりは喋れたけど、まだ遠慮してしまうところがあったので反省です。
会話の中で用語がわからないことがあった(コンストラクタ、ealry return、キーワード引数)。説明されると「あーあれか」となったので、その辺りの紐付けもしていきたいなーと思いました。

たくさんの収穫がありました。
運営の方々や一緒に活動をしてくださった方々など、本当にありがとうございました!

Share on

END
END
@aiandrox

 
目次