自動テストするぞ!tmux + PHPUnit + watchmedoで構築する自動ユニットテスト環境

こんにちは、斉藤です。
前回はテスト駆動開発という開発方法をご紹介しました
その中では"ユニットテストの実行"を主体に開発を行っていくことをお伝えしました。
今回は(余計な話も交えつつ)そのユニットテストの実行を自動化する方法をご紹介します。



* なぜ自動化?

ユニットテストを手動で走らせていませんか?
ユニットテストなど、開発プロセスの中で機械がやれることを手動で行うと、そこでスピード(and 効率)がガクッと下がります。機械任せにできるものは、以下のようなタスクがあります。


・ビルド
・ユニットテストの実行
・簡易なドキュメント、チェンジログの用意

手動で行うことにしていると、そのプロセスを実行することを忘れてしまったり、「めんどくさいよー」ってなってしまい、実行回数が減ってしまいます。
その結果、品質の低いアプリが生まれますよね・・・。
近年では、それらを改善するために継続的インテグレーションという習慣が生まれたりしています。
この習慣の中では、自動化できることは自動化しようととも言っていますので、それに倣って自動化できるところはどんどん自動化していきましょう!


* ツールを用意する

まずは、タイトルにあるこの三つのツールを用意します。


・tmux(screenでも可):ターミナルの画面を一度に複数表示できるようにする(場合によっては使わない)
・PHPUnit:ユニットテストを走らせるためのツール(使用している言語によって、変えてください)
・watchmedo:フォルダ内の監視をし、変更が起きたタイミングで、シェルスクリプトを走らせることが出来る

話が長くなりますので、具体的な解説は避けますが、単体で使っても使いやすいツールです。インストール方法はリンク先を参照してください。
tmux
PHPUnit
watchmedo

この三つのツールを組み合わせると、こんなことになります。


・tmuxによって、一つはエディタ、もう一つはユニットテストの結果を表示させる画面を一度に表示できる
・watchmedoによって、エディタでファイルを変更したタイミングで、PHPUnitを実行できる

これで、一々手動でユニットテストを実行させる手間を省くことが出来ます。

* 環境構築

それでは、構築してみます。
まずはターミナルを立ち上げ、tmuxを実行します。

次に、画面を複数表示させます。
tmuxでは、これをペインという方法で実現します(C-b % というキーバインドにアサインされています)。
これによって、それぞれの画面で別の作業をし、それを一度に確認できるようになりました!

テストをしたいPHPと、そのユニットテスト(PHPUnitで書かれたもの)を用意します。
今回はサンプルとして以下のものを用意しています。

テストをしたいPHP(SampleObject.class.php)


<?php
class SampleObject {
  private $foo;
  public function __construct()
  {
    $this->foo = "test string";
  }
  public function getFoo()
  {
    return $this->foo;
  }
}
?>

ユニットテスト(sampleTest.php)


<?php
require_once("/home/katsuya/auto_unit_test_blog/SampleObject.class.php");
class SampleTest extends PHPUnit_Framework_TestCase {
  public function testPushAndPop()
  {
    $object = new SampleObject();
    $this->assertEquals("test string", $object->getFoo());
  }
}
?>

そして、片方の画面で以下のようなスクリプトを叩きます。



<pre wp-pre-tag-5=""></pre>
nbsp;watchmedo shell-command --patterns="*.php" -c "clear; phpunit --colors ./"

これで、対象のファイル(ここではカレントディレクトリの中のPHPファイル)が変更されるたびに、ユニットテストすなわち"phpunit --colors ./"というコマンドが実行されます。
あとは、もう片方の画面でエディタを開いて開発をするだけですね!
保存するたびに、自動でユニットテストが走るので、効率よく開発を続けられます。

"自分の書いたコードを保存するというタイミングでフィードバックが得られる"ようになるので、開発効率が改善されるんじゃないかと思います。
ただし、それぞれのツールを使うための準備や知識が必要になりますので、状況に応じて、手動ユニットテストと使い分けてください。


* 備考

以上、自分では便利だ!と思っている環境をご紹介しましたが、最後にいくつか補足します。

- 継続的インテグレーションについて
冒頭でも触れましたが、アンテナを張っている方なら一度は聞いたことがあるんじゃないな?と思います。
アプリケーションを作っていく中で発生する作業の効率を良くするための習慣、と言われています。
本文で触れたように、ビルド、ユニットテスト、などなど機械に自動的にやらせた方が良いものはそうしよう、という手法もこの中の一つの習慣に入ります。
"継続的"という言葉は、一度きりではなく負担無く何度も続けられるようにする、という意味合いだと僕は思っています。
蛇足ですが、弊社はMonacaというサービスを"継続的"に運営、開発をしていますので、社内でもこういった習慣の取り入れを行い、少しでも開発体制を良くしようとしています。

- vimではバックアップファイルが作られること
自分はPHPの開発の際には、vimと呼ばれるエディタを使っています。
が、このエディタを今回の方法で使うと、vimが保存する度にバックアップを作る仕組み上、一度の保存に対してphpunitが複数回走ってしまいます。
今回は以下の設定を施して回避をしています(それでも、二回走ってしまう時があります・・・確実に避けられる方法を知っている方はぜひ。。。)。


・.vimrcファイルにset backupskip=/home/katsuya/auto_unit_test_blog/*  
・watchmedoに起動オプションとして、--patterns="*.php"を指定

- ユニットテストを保存するたびに走らせることの是非
以前、自分が今回紹介した環境を作りたい!と、周りの人に相談したところ、こんなことを言われました。
「保存するたびに、ユニットテストが走るのはそれはそれでうざくない?」
確かに。
軽量なプログラムならともかく、大規模になっていくとテストしていくコストも大きくなるので、そういった場合にはこの環境も見直しが必要になるでしょう。
そういった場合は、テストする対象を絞ったり、JenkinsなどのCIツールでユニットテストを走らせるなどの工夫が必要になると思います。

- PHP以外の他言語でも可能なこと
この記事は弊社のPHPプロというサイトに参照されることになりますので、PHP向けに書きました。
が、PHPUnitの部分を他のツールに読み替えると、JavaScript(QUnit)やobjective-c(GHUnit)にだって対応できます!
まずは、使っている言語のユニットテストフレームワークを探してみてください!



* 終わり

今回は自動でユニットテストを実行させる環境を構築する方法をご紹介しました。
皆さんも手動テストと使い分けて、良いアプリ開発を!