岩本隆史の日記帳(アーカイブ)

はてなダイアリーのサービス終了をうけて移行したものです。更新はしません。

Webアプリケーションをテスト駆動開発するには

TDDならモックの出番はない?

いつものように思いつきエントリなので、眉にツバをキュッキュとつけてお読みいただければ幸いです。

Pinto公開に向けて #18 ― RSpecのモックを使ってみた」では、Rackエントリポイントの実装と、そのテストコードを考えました。

で、あとから気づいたのが、これってTDD(あるいはBDD)じゃないんですよね。テストを先に書いていないので当たり前ですが。

ともあれ、モックだのスタブだのを気にする時点で、内部実装に依存したテストコードになっているわけです。それで良いのか、という問題意識が、私の中で鎌首をシャーともたげてきました。シャー。

TDDが唯一の正解ではないと思うものの、開発手法として魅力的なのは確かです。できればPintoはTDDで作ってみたい。

どうしたらWebアプリケーションをTDDで開発できるのか

そこで、どうしたらWebアプリケーションをTDDで開発できるのか考えてみました。といっても答えは単純で、あるHTTPリクエストについて仕様通りのHTTPレスポンスが返る、というテストコードをたくさん書き、実装し、リファクタリングしていけばよいのではないでしょうか。

テストコードはこんな感じです。

$LOAD_PATH << 'lib'
require 'pinto'

require 'rubygems'
require 'hpricot'
require 'rack'

describe "Pinto::RackServer#call with env for 'GET http://pinto.jp/'" do
  before do
    @env = Rack::MockRequest.env_for('http://pinto.jp/')
  end

  it 'should return 300 Multiple Choices' do
    response = Pinto::RackServer.new.call(@env)
    response[0].should == 300
  end

  it 'should return XHTML written in XML 1.0 and UTF-8' do
    response = Pinto::RackServer.new.call(@env)
    response[1]['Content-Type'].should == 'application/xhtml+xml; charset=UTF-8'
    Hpricot(response[2]).each_child do |elm|
      next unless elm.xmldecl?
      elm.to_s.should == '<?xml version="1.0" encoding="UTF-8"?>'
    end
  end
end

で、最低限の実装はこんな感じ。

module Pinto
  class RackServer
    def call(env)
      [
        300,
        {
          'Content-Type' => 'application/xhtml+xml; charset=UTF-8',
          'Content-Language' => 'en'
        },
        <<END
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Pinto</title>
</head>
<body>
</body>
</html>
END
      ]
    end
  end
end

こんなもの、Webアプリケーションでもなんでもないですが、テストとして書かれた仕様は完全に満たしています。TDDですよね。

あとは仕様をどんどん追加し、実装し、リファクタリングしていけばよいわけです。しばらく、この方法を試してみようと思っています。