読者です 読者をやめる 読者になる 読者になる

TDD と Git についてメモ

TDD Git

ついったーにつぶやいたものを中心にまとめました。
まだこれで正しいという確信を持てていないので、メモという位置付けでお願いします*1
なので追記する可能性が高いです。

  1. TDD でドキュメンテーションコメントを書くタイミング
  2. カテゴリを指定して実行するテストを分ける
  3. git stash の使い道

TDD でドキュメンテーションコメントを書くタイミング

ここでは Git を前提にしますけど、rebase 使えるならほかのものでも大丈夫なはずです。


TDD でいつドキュメンテーションコメントを書けばいいのか、というのは、

と、過去 (といっても半年も経ってないけど) ずっともやもやしてたんですが、
事前条件で楽できないかなーという考え - Logic Dice
に対する自分なりの答え *2 として昨日から今日にかけて
bleis-tift/GuardClauseBuilder · GitHub
を TDD で作ってみた際に、ちょうどいいタイミングを見つけました。


master から分岐した dev ブランチで開発していたとして、最初はドキュメンテーションコメントのことは考えずに TDD で開発していきます。
「考えずに」というのは、何もしないということです。完全に不要だから削除しておくか、というのもここでは考えず、たとえ IDE がドキュメンテーションコメントの雛形などを作ったとしても無視します。ドキュメンテーションコメントのことは頭から追い出して、本来の作業を進めてください。
で、push する前に、

$ git rebase -i master

として、pick をすべて edit にします。
そうすることでコミットを付け替えていく際に止まりますので、そのコミットで行った修正を見てドキュメンテーションコメントを追加します。
そして、修正したら

$ git add .
$ git rebase --continue

として rebase を続けます。


結局後で追加するのと同じなんですが、この方法だと「適切な順番で」ドキュメンテーションコメントが書けるので、「上から順番に」書く場合に比べて書きやすく、心理的負担も少ない気がします。


また、Eclipse 等の IDE ではデフォルトでクラスを作成した際に空のドキュメンテーションコメントを追加してきますが、テストにドキュメンテーションコメントは不要なのでそれもこの手順の中で削除します。
ここで注意してほしいのは、「ドキュメンテーションコメントが」不要なだけであって、コメント自体は不要ではないので、コメントが足りないなぁ、と思った場合もこの段階で追加します。


テストのヘルパ用に作ったクラスやメソッドがある場合、そのコードがテスト側にある場合はドキュメンテーションコメントは不要です。
あってもいいですが、簡単なものでいいでしょう。
テスト側からプロダクトコード側に移動した際に書きましょう。
ただし、ヘルパの移動もひとつのコミットとして、上で示した手順で「移動時にはただ移動のみを」行い、rebase 時にドキュメンテーションコメントを書きましょう。


この手順を行うことで、push 前に確認作業を挟むことができるという利点もあります。
さらに、「あ、このクラス名、ドキュメンテーションコメント書いてみたらこっちのほうがよかったな」と設計等について再考する時間を与えてもくれます。
実際、GuardClauseBuilder では GuardCondition クラスは rebase 前は Matcher という名前でした。


この方法では rebase -i のタイミング (つまり push のタイミング) までは定めていません。
この間隔が短すぎると TDD のリズムをくずしてしまいますし、設計を見直すという目的もあまり達成できません。
かといって長すぎると、今度はやる気が起きません。
これは難しい問題なのでこれから試行錯誤していく中で身につけたいと思います。
ただし、今回作った GuardClauseBuilder では長すぎたのは確かです。

カテゴリを指定して実行するテストを分ける

まだ実際に試せていないですが、次のような構成でテストを分けることを考えています。

  • 開発中に走らせるテスト
  • コミット時 (もしくは push 時) に走らせるテスト
  • デイリービルドで走らせるテスト

一番上は一番実行頻度の高いもので、開発者が明示的にテストを実行します。開発者のためのテストという位置付けです。
下の 2 つは CI ツールによって実行されるテストで、コミット時に走らせるテストはスモークテスト、デイリービルドで走らせるテストは結合テスト (というより単体テストには含めることのできない重いテストなどもすべて走らせるテスト)、という位置付けです。


この 3 つを分けるために、前はテストプロジェクトやフォルダ単位で分けることを考えていたのですが、NUnit/JUnit 共に Category という機能があるので、今はこれを使うことを考えています。


デイリービルドで走らせるテストというのは、実行するために時間が必要であまり頻繁には実行したくないようなテストも実行することになりますが、ようは全部のテストを実行するだけなので特別な指定は不要です。
しかし、開発中に走らせるテストとコミット時に走らせるテストでは重いテストを実行したくありませんので、デイリービルドでのみ走らせるテストには SlowTest などといったカテゴリを指定しておきます。
NUnit では、exclude オプションによって除外するカテゴリが指定できる*3ので、開発中に走らせるテストではこのカテゴリを除外しておきます。


コミット時に走らせるテストというのは、スモークテストという位置付けなので、開発中に走らせるテストよりも少なくなります。
なので、それらのテストに SmokeTest などといったカテゴリを指定しておきます。
NUnit では、include オプションによって実行するカテゴリの指定ができるので、コミット時に走らせるテストではこのカテゴリを指定しておきます。


こうすることで、開発中にはある程度のテストを、コミット時にはスモークテストを、デイリービルドではすべてのテストを実行できます。

git stash の使い道

stash 本来の使い方というのは、「作業をいったんおいておく」というものです。
しかし、stash を使わずに commit してしまった方が安心だし使いやすいです*4
そのため stash は最近あまり使っていなかったのですが、全然使ってなかったわけではありません。
でも自分が何をやっているのか意識せずに使っており、昨日「あ、こういうときに git stash 使ってるじゃん!」と気が付いたので書いておきます。


たとえば、some-branch というブランチで作業していたとしましょう。
そして何か別の作業が入ってほかのブランチに移ったとしましょう。
作業を終え、いつもなら some-branch に戻るのですが、今日はたまたま切り替え作業を忘れていて、some-branch ではないブランチで作業をしてしまったとします。


その作業をコミットしてしまった場合は cherry pick なり何なりで簡単にその作業を some-branch に反映できます*5
しかし、まだコミットしていない場合、いちいちコミットして cherry pick、reset というのも面倒です。
そこで、その作業をすべてインデックスに追加して、git stash し、ブランチを切り替えて git stash pop します。
本来の stash の用途とは違いますが、割と便利な stash の使い方です。

*1:突っ込み歓迎!

*2:絵空事をある程度実現する、という意味での答え。エントリの内容自体についてはまた別の答えを持ってる

*3:JUnit でどうやるかはまだ見ていないけど、多分同等の指定方法があるはず

*4:git stash したものを間違って消してしまった場合、戻すのが面倒。少なくとも普段使うようなコマンドではない

*5:そして reset して間違った場所での作業はなかったことにする