ペアプロ二日目: かおるんさんと googletest でペアプロ

はじめに

ある金曜日、上司がWyCashという債券ポートフォリオ管理システムの見込み客であるピーターを紹介しようとワード・カニンガムのところにやって来た。ピーターは「これらの機能にとても感銘しました。しかし、御社は米ドル建て債券しか取り扱わないことに気付きました。新しい債券ファンドを始めようとしているのですが、戦略上、異なる通貨の債券を取り扱う必要があります」と言った。上司はカニンガムに向かって、「どうだい、できるかね」と言った。(ケントベック『テスト駆動開発入門』)

僕らも、集合場所にやってきた。できるかどうかの質問には明確に答えられない。ただ、やってみようと思う。集合場所は分倍河原。そこには今回のお相手のかおるんさんが待っている。今日も新たにペアプロに挑戦だ。

今回のお題

今回は事前に twitter の Direct Message で話して、ケントベックの『テスト駆動開発入門』のコードを書き写そうということになった。写経って呼ばれているヤツだ。

テスト駆動開発入門』は TDD のバイブル的位置付けの本だ。この本を写経したことのない人がやっていることは TDD ではないと言ってもいいくらい、 TDD を実践するにあたっては大事な本だ。自分も折々、色々な言語でこの本を写経していて、この本を大切にしている。

TDDの伝道師こと t-wada さんも言っている。


テスト駆動開発入門』をペアプロで写経。「どうだい、できるかね」と、サンプルコードが語るとおり、TDDを学んでいく。これが今回のお題だ。

今回のお相手

今回のお相手は、かおるんダイアリーが有名な、かおるんさんだ。TracやSCRUMなどのトピックで色々活動されている方だ。また、TDD Boot Camp 名古屋以降、東のイケメンということで名が通っている。


実はかおるんさんとは、以前も密会と称して、居酒屋でペアプロをしたことがある。今思えば、これがペアプロ日記の原点となっているのかもしれない。そんな想いもあり、第二回は、かおるんさんにお願いすることにした。

今回の道具

C++ & googletest

今回は googletest を使って C++ でプログラミングをした。

googletest は の C++ 用のユニットテスティングフレームワークで、 Google 謹製だけあって GoogleTest は素敵な感じに仕上がっている。また、最近はマニュアルの日本語訳も登場していて、一層、導入しやすい環境になってきている。

make

C++ で使うビルドツールは sconswaf など選択肢が増えてきている。特に、 make では工夫しないとできないヘッダファイルの依存関係の解決などをやってくれたりして、後発のツールに乗り換える人も多いようだ。特に、 TDD のリズムを作る場合は、関連するヘッダファイルが書き換わったことをビルドツールが感知してくれることは重要になる。

ただ今回は、これらのツールを使うのではなく、ヘッダファイルの依存関係を解決できるように Makefile を作成して、 make を使用することにした。

CXX = g++

CXXFLAGS = -O2
LDFLAGS = -lpthread -lgmock_main -lgtest -lgmock 

SRCS_ALL = ${wildcard *.cpp}
SRCS_TEST = ${wildcard *Test.cpp}
SRCS = ${filter-out ${SRCS_TEST}, ${SRCS_ALL}}
OBJS_ALL = ${SRCS_ALL:.cpp=.o}
OBJS = ${SRCS:.cpp=.o}
BINS_TEST = ${SRCS_TEST:.cpp=.bin}
TESTS = ${SRCS_TEST:.cpp=}

all : test
test : ${TESTS}

.SUFFIXES : .cpp .make
.cpp.make :
	${CXX} ${CXXFLAGS} -MM -MG  $< > $@
	echo "	${CXX} ${CXXFLAGS} -c $< -o $*.o" >> $@

${OBJS_ALL} : %.o: %.make
	make -f $< $@
	rm -f $<

${BINS_TEST} : %.bin : %.o ${OBJS}
	${CXX} ${OBJS} $< ${CXXFLAGS} ${LDFLAGS} -o $@

${TESTS} : % : %.bin
	./$< --gtest_output=xml:$@.report.xml

clean :
	rm -f *.a
	rm -f *.o
	rm -f *.make
	rm -f *Test.bin
	rm -f *Test.report.xml
emacs

エディタは emacs を使った。 googletest が emacs 形式のエラーメッセージを出力してくれるのも心地よい。以下のような設定を .emacs に追加した。

(global-set-key "\M-m"   'compile)
(global-set-key [M-down] 'next-error)
(global-set-key [M-up]   '(lambda () (interactive) (next-error -1)))

(defface gtest-face-green '((t (:foreground "green"))) nil)
(defface gtest-face-red '((t (:foreground "red"))) nil)
(defvar gtest-face-green 'gtest-face-green)
(defvar gtest-face-red 'gtest-face-red)
(defadvice font-lock-mode (before my-font-lock-mode ())
  (font-lock-add-keywords
   major-mode
   '(("[[]==========[]]" 0 gtest-face-green append)
     ("[[]----------[]]" 0 gtest-face-green append)
     ("[[] RUN      []]" 0 gtest-face-green append)
     ("[[]       OK []]" 0 gtest-face-green append)
     ("[[]  PASSED  []]" 0 gtest-face-green append)
     ("[[]  FAILED  []]" 0 gtest-face-red append)
     )))
(ad-enable-advice 'font-lock-mode 'before 'my-font-lock-mode)
(ad-activate 'font-lock-mode)

ここでは

  • Meta-m で make が走る
  • Meta-↑ / Meta-↓ でエラー箇所にジャンプする
  • テストの結果に色をつける*1

というような設定をしている。実際にテストを実行させるとこんな感じだ。


git-now

git-now は sinsoku_listy さんが考案した、テンポラリ用のコミットを作成するためのコマンドだ。自分も実装をお手伝いして Gist に登録した。使い方は sinosku_listy さんのブログで紹介されている。

実際の作業

まずは ToDo リスト

テスト駆動開発入門』では、何をしているかを明確にするために ToDo リストを作成している。今回の作業でもそれにしたがって、 ToDo リストを作成した。今回は ToDo というファイルを作成して、そのファイルを変更していくようにした。

ToDo

  レートが2:1の場合、 $5 +10 CHF = $10
  $5*2=$10
一歩進むごとに git-now

TDDの学習の時には一歩一歩何をやったかを記録していきたい。そこで役に立つのが git-now だ。一歩進むごとに git-now 。コマンドラインで「 git now 」と入力するたびに、変更が記録されていく。「ここで git-now 」。これが僕等の心地よいリズムとなった。

テストを書く

TDDではまずテストコードを書く。『テスト駆動開発入門』にあるとおり、 testMultiplication から書き始めた。もちろん、ここでもテストを書いて「ここで git-now」だ。

MoneyTest.cpp

#include <gtest/gtest.h>

class MoneyTest : public ::testing::Test
{
	
};

TEST_F( MoneyTest, testMultiplication )
{
    Dollar five;
    five.times( 2 );
    EXPECT_EQ( 10, five.amount );
}
プロダクトコードを書く

テストコードに対応するプロダクトコードを書いていく。 testMultipication に対応して、 times メソッドを作成した。もちろん、ここでもコードを書いて「ここで git-now」だ。

Money.hpp

class Dollar
{
public:

    Dollar( int amount ) : amount( 5 * 2 ) {
    }

    void times( int multiplier ) {
    }

    int amount;
};

なお、今回は、写経することが目的なのでヘッダファイルに実装も書いていったが、実際には、ソースコードに書くことになるだろう。

C++特有の部分に気を配る

テスト駆動開発入門』の Part 1 はJavaで書かれている。基本はこれをそのまま書き写せばよいのだけれど、使う言語によっては不自然になってしまうこともある。

C++を使っていると、 times や equals は operator* や operator== として書く方が自然な気がする。今回は、まず本のとおりに写経して、 ToDo リストにメンバ関数名の変更を記載。その後、コードを書き換えることにした。

ToDo (抜粋)

  hushCode()->C++いらない
  equalsをoperator==に変える
  timesをoperator*に変える

まとめ

こんな感じのことを繰り替えして Maney を作り上げていった。今回は時間の関係で途中までしか写経できなかった。また続きをやりたいと思う。

やはりこの本は写経する度に色々な発見がある。出会う度に再び TDD のリズムを思い出させてくれる、そんな本だ。

カニンガムはコードをビルドにチェックインし、上司に自信を持って報告した。(ケントベック『テスト駆動開発入門』)

僕らも github にペアで書いたコードを push した。 git-now によって記録された一歩一歩の軌跡が上への報告の代わりだ。これでまた少し、自信をもって TDD ができるかもしれない。

https://github.com/toshi-kawanishi/money-cpp-gtest

*1:きちんとやるのであれば compilation mode に ansi-color を設定するなどの方法があるが、ここでは、とりあえず、この形で色を付けている。