連載「DB2 と Ruby on Rail」の第 1 回では IBM_DB Ruby ドライバー、Rails マイグレーション、そして Team Room アプリケーションについて説明し、続く第 2 回では Rails アプリケーションで DB2® pureXML™ サポートを利用するために第 1 回で作成した Team Room アプリケーションを拡張する手順を説明しました。
Team Room アプリケーションが拡張され、複雑さを増してきたところで、アプリケーションが期待通りに動作することを確かめなければなりません。そこで当然、次のステップとなるのは Team Room アプリケーションのテストです。この第 3 回目の記事では、DB2 on Rails 環境ではテストがどのようにして行われるのか、そして Ruby on Rails フレームワークではテストをいかに簡単に作成できるかを紹介します。
Rails フレームワークは、テスト・サポートが組み込まれているおかげで、Web アプリケーションをテストするのに便利な手段となります。Rails でテストを作成する時機は、コア・アプリケーションができあがって実行できるようになってからでも、アプリケーションを作成しながらでも、さらにはアプリケーションを作成する前 (テスト主導型開発 (TDD) と呼ばれます) でも構いません。
新規 Rails プロジェクトを作成すると、Rails によって自動的にテスト・インフラストラクチャーが生成されます。Rails の Team Room プロジェクトのディレクトリーを調べると、D:\rails\teamroom\ の下には \test サブディレクトリーがあり、\test の下には 5 つのディレクトリーと 1 つのヘルパー・ファイルが作成されていることがわかります。
リスト 1. test ディレクトリーの内容
/unit
/functional
/fixtures
/integration
/mocks
test_helper.rb
|
すべてのテストは /test ディレクトリーに入れ、それぞれのテストをその特性と機能に応じて 5 つのサブディレクトリーのいずれかに配置してください。以下に、/test ディレクトリーに含まれる各コンポーネントについて説明します。
Rails では、モデルのテスト用に作成されたテストは単体テストと呼ばれます。通常はモデルごとに 1 つの単体テストを作成します。単体テストでは、モデルを壊す可能性のあるすべてのものをテストしてください。基本テストには検証コードとアサーションのテスト、そして CRUD (Create、Read、Update、Delete) といったデータベース操作のテストを含める必要があります。
コントローラーのテスト用に作成されたテストは機能テストと呼ばれます。機能テストは単体テストより上位レベルでアプリケーションをテストするためのものです。この場合も同じく、使用するコントローラーごとに 1 つの機能テストを作成します。機能テストでは例えば、Web ページへのリクエストが正常に完了するか、正しいページにリダイレクトされるか、認証が適切に行われるか、そして特定のアクションに対して正しい応答が行われるかをテストします。
フィクスチャーはモデル内のコンテンツを指定します。フィクスチャーにはデータを指定し、単体テストを実行するときにそのデータをロードするように Rails に指示してください。これはいわば、DB2 でのインポートまたはロード関数のようなものです。
モックとは、制御の及ばない外部システムとの相互作用ではなく、Rails プロジェクトのスコープ内にある重要な機能のテストに専念できるようにするための「偽物の」オブジェクトのことです。例えば、Team Room アプリケーションでは新しい文書が特定のサブジェクトに追加されると、そのサブジェクトをサブスクライブしているユーザーに E メールで新規文書の追加が通知されます。このアプリケーションにはユーザーによって提供された E メールが実際に有効な E メール・アドレスであるかどうかを検証する E メール検証システムが用意されていないため、ユーザーの E メール・アドレスの有効性についての確認は、E メール・アカウント・プロバイダーやドメイン・サーバーからのエラー・レポートに依存しています。モック・テスト・メソッドを作成すれば、外部ネットワークにアクセスしたり、E メール検証システムを準備したりしなくても、Team Room の通知機能をテストすることができます。
結合テストとは、複数のコントローラーとアクションにまたがるテストのことです。その名前が示唆するように、このテストではさまざまなコントローラーとアクションが期待通りに連動するかどうかを確認します。結合テストは Rails アプリケーションに含まれる各種コンポーネント間の上位レベルでの相互作用を扱うため、通常はより総合的なテストとなります。
test_helper.rb ファイルには、複数のテスト・ケースに共通する多くのデフォルト Rails 動作が設定されます。例えば test_helper.rb では、Rails がテストの際に (database.yml ファイルで構成される) テスト・データベースを使用するように、RAILS_ENV 環境変数が「test」に設定されています。すべての単体テストは、Rails の test_helper.rb ファイルをロードします。また、test_helper.rb にはカスタム・アサーションを定義することも可能です。定義されたカスタム・アサーションは、同じ Rails アプリケーション内で複数のテストが共有し、使用することができます。
連載「DB2 と Ruby on Rails」の第 1 回では、DB2 XMLDB 開発データベースに接続するために D:\rails\teamroom\config\database.yml ファイルを編集しました。YAML ファイルの「development」セクションの下には「test」と「production」という追加セクションがありますが、前回はこの 2 つのセクションには明示的に入力していません。それぞれの名前が示すように、「test」はテスト・データベース環境を指定するセクションで、「production」は実動データベース環境を指定するセクションです。現実に、開発環境とテスト環境で同じデータベースを指定する場合がありますが、実動環境は、開発データベースやテスト・データベースとは明らかに異なります。それでは早速、TESTDB テスト・データベースを作成し、database.yml ファイルにテスト環境をセットアップしてみましょう。
以下のコマンドを実行して TESTDB データベースを作成します。
db2 create db testdb using codeset utf-8 territory us
database.yml を以下のように編集します。
リスト 2. database.yml ファイル
# IBM DB2 Database configuration file
#
# Install the IBM DB2 driver and get assistance from:
# http://www.alphaworks.ibm.com/tech/db2onrails
development:
adapter: ibm_db
database: xmldb
username: user
password: secret
schema: teamroom
application: TeamRoom
account: devuser
workstation: devbox
# == remote TCP/IP connection (required when no local database catalog entry available)
# host: bigserver // fully qualified hostname or IP address
# port: 50000 // data server TCP/IP port number
test:
adapter: ibm_db
database: testdb
username: testuser
password: secret
schema: teamroom
application: TeamRoom
account: testuser
workstation: testbox
production:
adapter: ibm_db
database: proddb
username: produser
password: secret
schema: teamroom
application: TeamRoom
account: produser
workstation: prodbox
|
テストを行うためには、テスト・データベースと開発データベースの表構造が確実に同じになるようにしなければなりません。そこで、テスト環境の作成を支援する Rake コマンドを使用すれば、スキーマをロードするための DDL スクリプトを管理する必要がなくなります。rake --tasks コマンドを実行すると、テスト・データベースを作成、またはこれを空にするための関連コマンドがいくつか表示されます。
リスト 3. rake --tasks の出力
rake db:test:clone # Recreate the test database from the current
# environment's database schema
rake db:test:clone_structure # Recreate the test databases from the development
# structure
rake db:test:prepare # Prepare the test database and load the schema
rake db:test:purge # Empty the test database
|
データベースに表を作成するには、rake db:test:prepare コマンドを使用します。このコマンドを実行すると、開発データベースのスキーマがテスト・データベースに複製されます。
リスト 4. rake db:test:prepare
D:\rails\teamroom> rake db:test:prepare
(in D:\rails\teamroom)
|
これで、testdb データベースに接続して、すべての表が正常に作成されたことを確認できます。
リスト 5. testdb に含まれる表
D:\rails\teamroom>db2 list tables for schema teamroom
Table/View Schema Type Creation time
------------------------------- --------------- ----- --------------------------
DOCUMENTS TEAMROOM T 2007-06-05-11.21.46.343002
SCHEMA_INFO TEAMROOM T 2007-06-05-11.21.48.306001
SUBJECTS TEAMROOM T 2007-06-05-11.21.46.633003
SUBJECTS_SUBSCRIPTIONS TEAMROOM T 2007-06-05-11.21.47.004000
SUBSCRIPTIONS TEAMROOM T 2007-06-05-11.21.47.194005
USERS TEAMROOM T 2007-06-05-11.21.47.595003
XML_CONTENTS TEAMROOM T 2007-06-05-11.21.47.955001
7 record(s) selected.
|
テスト・データベースにはすべての表が定義されたので、テスト・データをロードする準備は万端です。テスト・データのロードは SQL の挿入またはインポートによって手動で行うこともできますが、この後説明するように、テキスト・フィクスチャーを利用すると面倒を省けます (同時に、管理もしやすくなります)。
Ruby (1.8 以降) に付属している重要なライブラリーの 1 つとして挙げられるのは、test/unit です。Ruby テスト・スクリプトを作成するには以下の手順に従います。
- .rb ファイルの先頭に「
"require 'test/unit'"」を指定します。この文によって、Test::Unit モジュールがロードされます。 -
require文の後に、このクラスが Test::Unit::TestCase のサブクラスであることを示すクラス宣言を追加する必要があります (リスト 6 を参照)。
リスト 6. 単体テストのための「"require 'test/unit'"」の指定
require 'test/unit'
class SubTestCase < Test::Unit::TestCase
...
end
|
Team Room アプリケーション・パスの test\unit サブディレクトリーには .rb ファイルがあります。これらのファイルは、scaffold が生成されたことから作成されたすべてのモデル・オブジェクトに対応し、ファイルのオブジェクト名には「_test」が追加されます。
test\unit サブディレクトリーの下にテスト・スクリプトを作成するときには、require 'test/unit' 文を指定する必要はありません。既存の require 文で参照される test_helper.rb ファイルに必要な情報が既に含まれているからです。
リスト 7. test\unit パスのリスト
D:\rails\teamroom\test\unit>dir
Volume in drive D has no label.
Volume Serial Number is C8D3-5819
Directory of D:\rails\teamroom\test\unit
06/05/2007 09:27 AM <DIR> .
06/05/2007 09:27 AM <DIR> ..
06/05/2007 09:27 AM 208 customer_info_test.rb
05/31/2007 07:42 PM 199 document_test.rb
06/02/2007 05:14 PM 251 subjects_subscription_test.rb
05/31/2007 07:42 PM 315 subject_test.rb
05/31/2007 07:42 PM 1,211 subscription_mailer_test.rb
05/31/2007 07:42 PM 207 subscription_test.rb
05/31/2007 07:42 PM 191 user_test.rb
05/31/2007 07:42 PM 204 xml_content_test.rb
8 File(s) 2,786 bytes
2 Dir(s) 15,359,959,040 bytes free
|
Ruby では、すべてのテスト・メソッド名は「test」という 4 文字で始まります。この 4 文字で始まっていない場合、テスト・フレームワークはテストとして認識しません。「test」プレフィックスのないメソッドは通常の Ruby メソッドとして扱われるため、テスト・フレームワークによって自動的に実行されることはありません。
リスト 8. 一般的な単体テスト
require File.dirname(__FILE__) + '/../test_helper'
class Sub_Test < Test::Unit::TestCase
def test_truth
assert true
end
end
|
ここで、sub_test.rb という名前を付けてファイルを保管します。このファイルを実行すると、以下の内容が出力されます。
リスト 9. sub_test.rb の実行
D:\rails\teamroom\test\unit>ruby sub_test.rb
Loaded suite sub_test
Started
.
Finished in 0.631 seconds.
1 tests, 1 assertions, 0 failures, 0 errors
|
1 つのアサーションを実行する上記の単純なテスト・シナリオは、「assert true」文により成功したことがわかります。アサーションとは、すなわちテストのことです。次のセクションで説明するように、Rails アプリケーションのテストには数々の assert 文を使用することができます。
Rails では、script/generate model、script/generate controller、script/generate scaffold によって作成されたすべてのモデルおよびコントローラーが、対応するテスト・スタブを test サブディレクトリー内に作成します。これらのテスト・スタブを使用する場合には、「"require 'test/unit'"」を指定する必要はありません。
アサーションはアプリケーションまたはモジュールの事前/事後の状態を検証し、有効な状態であることを確認します。Test::Unit アサーションは基本パターンに従うため、期待される結果が最初のパラメーターに、実際の結果が 2 番目のパラメーターに入ります。期待される値と実際の値が一致しない場合、何が問題だったのかを説明するメッセージが生成されます。
中心的な Ruby アサーションのリストについては、Test::Unit::Assertions を参照してください。
他にも Rails 開発者が使用できる数多くのアサーションについては、 Module Test::Unit::Assertions Information を確認してください。
アサーションは前述したように、有効な状態を確認するために使用されます。それでは有効な状態とは一体何によって定義されるのでしょう。
有効な状態のほとんどは、コード内の検証結果に左右されます。
入力データは、データベースに保管する前でも検証することができます。それにはカスタム検証を定義するか、あるいは一連の標準検証を使用します。属性の名前、長さ、フォーマットのチェックなどの標準的な検証を行うには、ActiveRecord に用意された検証を利用することができます。
検証メソッドをモデルに追加すると、オブジェクトがデータベースに保管される前に検証が行われます。オブジェクトは検証の結果、合格するとデータベースに書き込まれます。検証の結果が失敗だった場合は、そのオブジェクトに対して失敗した検証メソッドに関連するエラー・メッセージがエラー・リストに追加されます。このリストを表示すれば、ユーザーが適切な処置を講じて失敗を解決することができます。
この記事では、ActiveRecord の一連のバリデーターを使ってモデルを検証する例を紹介します。
サンプル・アプリケーション Team Room では、例えばサブジェクトについて以下の検証を行う必要があるとします。
- サブジェクトに関連付けられたすべての文書オブジェクトが有効なオブジェクトであること
- サブジェクト名が空でないこと
- サブジェクト名の長さが 20 文字以下であること
上記の検証が確実に行われるようにするためには、標準検証メソッドのいくつかを利用することができます。app\models\subject.rb に追加する検証は以下のとおりです。
リスト 10. app\models\subject.rb に含まれる検証
validates_associated :documents
validates_associated :subscriptions
validates_presence_of :name
validates_length_of :name,
:maximum => 20, # maximum 20 characters
:too_long => "is too long, maximum 20 characters"
validates_numericality_of :size, # value is numeric and only integer accepted
:only_integer => true,
:greater_than => 0
validates_presence_of :description
validates_length_of :tag,
:maximum => 10, # maximum 10 characters
:too_long => "is too long, maximum 10 characters"
|
「validates_associated」メソッドによって、サブジェクトに関連付けられたすべての文書が有効であることをチェックし、「validates_presence_of」メソッドによってサブジェクト名が空でないことをチェックします。
サブジェクト名の長さが 20 文字以下であることをチェックするには、「validates_length_of」メソッドを使います。「maximum」は、サブジェクト名の最大サイズを指定するための構成オプションです。サブジェクト名が 20 文字を超えている場合に生成されるエラー・メッセージを指定する「too_long」オプションは、「message」オプションに代わって使用されます。「too_long」メッセージのデフォルトは「is too long (maximum is %d characters)」(「が長すぎます (最大 %d 文字です)」) です。
これで、サブジェクトの入力データは上記に設定したルールに従って検証されるようになります。次に、ユーザーが問題のあるデータを入力した場合には、その入力データを修正できるようにエラー・メッセージのリストがユーザーに表示されるようにしなければなりません。
この場合に役立つ ActionView メソッドには以下のものがあります。
- error_message_on - 指定されたオブジェクト属性に関するエラー・ストリングを返します。
- error_messages_for - 指定されたオブジェクトのエラー・リストを返します。
これらのメソッドについての詳細を調べるには、ここをクリックしてください。
Team Room の場合、新しいサブジェクトに対して入力されたすべての入力データのエラー・メッセージを一覧表示するには、app\views\subjects\_form.rhtml の先頭に以下のメソッドを追加します。
リスト 11. 入力データのエラー・メッセージ
<%= error_messages_for 'subject' %>
|
このメソッドを呼び出すと、すべてのエラー・メッセージ (存在する場合) が含まれる div が返されるので、簡単にエラー・メッセージを表示することができます。
図 1. 長すぎるサブジェクト名を入力した場合のエラー・メッセージ
ここをクリックすると、クラス・スコープ内に定義可能な Active Record のモデル検証のリストを見ることができます。
これで、サブジェクト・モデル検証の準備ができたので、アサーションを使って上記の検証を実際にテストすることができます。
これからアサーションを使用して、SUBJECTS 表に関連付けられたモデルをテストします。SUBJECTS 表に関連付けられたモデルのなかに、表に必要な情報が有効な長さで入力されていることを確認するというものがあります。このような検証は、バックエンド・データベースに不必要な負荷をかけない上で重要です。テストする検証内容については、\app\models\subject.rb に概略が示されています (リスト 10 を参照)。
「test_invalid_with_empty_values」メソッドは、値が空であるというエラー条件のアサーションを説明する単純な例です。この「test_invalid_with_empty_values」メソッドで、サブジェクト値が空の場合にエラーになるかどうかをテストすることにします。
リスト 12. テスト・メソッド「test_invalid_with_empty_values
require File.dirname(__FILE__) + '/../test_helper'
class SubjectTest < Test::Unit::TestCase
# Tests validation failure using empty values
def test_invalid_with_empty_values
subject = Subject.new
assert !subject.valid?
assert subject.errors.invalid?(:name)
assert subject.errors.invalid?(:size)
assert subject.errors.invalid?(:description)
end
...
|
有効なサブジェクト・データをアサートする 2 番目のテストと、誤った長さの TAG を指定した場合に期待されるエラー・メッセージが表示されるかどうかを調べる 3 番目のテストを追加します。
この時点で、test/unit/subject_test.rb には以下の 3 つのテスト・メソッドがあるはずです。
リスト 13. subject_test.rb のテスト・メソッド
require File.dirname(__FILE__) + '/../test_helper'
class SubjectTest < Test::Unit::TestCase
# Tests validation failure using empty values
def test_invalid_with_empty_values
subject = Subject.new
assert !subject.valid?
assert subject.errors.invalid?(:name)
assert subject.errors.invalid?(:size)
assert subject.errors.invalid?(:description)
end
# Tests validation using valid data
def test_valid_subject
subject = Subject.new(:name=>"Perl",
:size=>2,
:description=>"test",
:tag=>"123456789")
assert subject.valid?
end
# Tests invalid TAG length
def test_invalid_tag_length
subject = Subject.new(:name=>"AJAX",
:size=>3,
:description=>"test",
:tag=>"abcdefghijklm")
assert !subject.valid?
assert_equal "is too long, maximum 10 characters",subject.errors.on(:tag)
end
end
|
上記の単体テストが成功すると、以下の内容が出力されます。
リスト 14. サブジェクト・単体テストの実行
D:\rails\teamroom>ruby test/unit/subject_test.rb
Loaded suite subject_test
Started
...
Finished in 13.891 seconds.
3 tests, 7 assertions, 0 failures, 0 errors
|
出力にある 3 つのテストとは subject_test.rb ファイルに定義された 3 つのテスト・メソッドのことで、7 つのアサーションとはこのファイルに含まれるすべての assert 文のことです。そして「.」は注 3 で前述したように、合格したことを意味します。
上記の subject_test.rb の例には、リスト 15 の 7 つのアサーションが含まれます。
リスト 15. subject_test.rb 内のアサーション
assert !subject.valid?
assert subject.errors.invalid?(:name)
assert subject.errors.invalid?(:size)
assert subject.errors.invalid?(:description)
assert subject.valid?
assert !subject.valid?
assert_equal "is too long, maximum 10 characters",subject.errors.on(:tag)
|
subject_test.rb に含まれる 3 つのテストは、リスト 16 に示すとおりです。
リスト 16. subject_test.rb 内のテスト・メソッド
test_invalid_with_empty_values
test_valid_subject
test_invalid_tag_length
|
Rails アプリケーションをテストするには、ブラウザーに手作業で値を入力する代わりにテスト・フィクスチャーを使ってサンプル・データをデータベース表にロードするという方法もあります。フィクスチャーを使用すると、事前定義されたデータ値をデータベースに入力してからテストを実行することができます。フィクスチャーの形式は、YAML またはコンマ区切り値 (CSV) のいずれかです。フィクスチャーはデータベースには依存しないため、同じ 1 つのフィクスチャーを使ってさまざまなデータベース・システムに対して Rails アプリケーションをテストすることができます。
これからフィクスチャーを使って、Team Room アプリケーションのサブジェクトとサブスクリプションをテストします。このテストでは YAML フィクスチャーを使用するので、/test/fixtures ディレクトリーに配置された subjects.yml ファイルを編集します。Rails はサブジェクトの単体テストを生成するときに、対応する空の subjects.yml ファイルを作成します。ruby script/generate model を実行して新しいモデルを作成するとき、あるいは ruby script/generate scaffold を実行して scaffold を生成するときには、フィクスチャー・スタブが自動的に作成されて /test/fixtures ディレクトリーに配置されます。
subjects.yml を編集して 24 の異なるサブジェクトを設定しました。/test/fixtures/subject.yml は、この記事の「ダウンロード」セクションに用意したサンプル・コードのなかにあります。それぞれのフィクスチャーには、コロンで区切られたキーと値のペアのリストが続く名前が付けられています。
subjects.yml のサンプル・コンテンツは以下のとおりです。
リスト 17. subjects.yml のサンプル・コンテンツ
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
photography:
id: 1
name: Photography
size: 0
description: Digital Photos, images
tag: portraits
gardening:
id: 2
name: Gardening
size: 0
description: Gardening info
tag: flowers
golf:
id: 3
name: Golf
size: 0
description: Golf information, golf club, golf course discount available to members
tag: golf
tennis:
id: 4
name: Tennis
size: 0
description: Tennis information, tennis club, tennis court bookings
tag: tennis
<etc ..>
|
Rails フィクスチャーのロード・メカニズムはすでに用意されているので、Rails にテスト・データをロードさせるためのコードを追加する必要はありません。ここではリスト 13 の /test/unit/subject_test.rb を変更して、フィクスチャーを使用してテストするためのコードを追加してあります。
リスト 18. /test/unit/subject_test.rb に含まれるフィクスチャー関連のエントリー
require File.dirname(__FILE__) + '/../test_helper'
class SubjectTest < Test::Unit::TestCase
fixtures :subjects
# count the number of subject fixtures
def test_subject_fixtures
assert_equal 24, Subject.count
end
...
# Previous test methods and assertions are listed below
...
end
|
fixtures メソッドは、テスト・ケースに含まれる各テスト・メソッドを開始するたびに、指定されたモデル名に対応するフィクスチャーを自動的にロードします。デフォルトで、:subjects は Rails に ubjects.yml ファイルからサンプル・データをロードするように指示します。上記では、24 すべてのサブジェクトが正しくロードされることをテストするために「test_subject_fixtures」メソッドが追加されています。
ruby test/unit/subject_test.rb によってこのテストを実行すると、以下の内容が出力されます。
リスト 19. フィクスチャーを使用したサブジェクトの単体テストの出力
D:\rails\teamroom>ruby test/unit/subject_test.rb
Loaded suite test/unit/subject_test
Started
....
Finished in 3.15 seconds.
4 tests, 8 assertions, 0 failures, 0 errors
|
WEBrick サーバーを起動し、登録済みユーザーとしてログインしているという前提では、http://localhost:3000/subjects/list までブラウズすると、 サブスクリプション対象として 24 のサブジェクトが選択可能になっているはずです。
図 2. 設定されたサブジェクト・エントリーのスクリーンショット
場合によっては、ERb (Embedded Ruby) と動的フィクスチャーを併せて使用してフィクスチャー・データを生成しなければならないこともあります。最もありがちな例は、テストの実行に伴った実際のタイムスタンプを生成する場合です。この場合、Ruby コードを実行するには <% ... %> を使用します。さらに <%= ... %> を使用すれば、Ruby コードを実行できるだけでなく、その結果を表示することもできます。動的フィクスチャーと ERb の使い方については、この後の機能テストおよびパフォーマンス・テストの実行方法に関するセクションで説明します。
もう一歩高度なフィクスチャーの使い方としては、フィクスチャーを使ってサブジェクトとサブスクリプションとの関係をテストすることもできます。もちろん、http://localhost:3000/subjects/list までブラウズし、現行のログイン・ユーザーとしてサブスクライブしたい複数のサブジェクトにチェック・マークを付けてから Team Room のサブジェクトとサブスクリプションの関係をテストすることもできますが、多数のサブジェクトが関係する多くのユーザー・サブスクリプションをテストするとなると、この方法はかなり面倒になります。なぜなら、手動で多数のユーザー・サブスクリプションを作成した上で、ログインしてサブスクライブするサブジェクトにチェック・マークを付けるという作業を該当するユーザーごとに繰り返さなければならないからです。
それよりも効率的にモデル間の多対多の関係をテストする方法となるのは、結合表のデータが含まれる新しいフィクスチャーを作成することです。前回の第 2 回では、SUBJECTS_SUBSCRIPTIONS 表を作成して SUBJECTS 表と SUBSCRIPTIONS 表との多対多の関係を表し、データベースが確実に正規化されるようにしました。この SUBJECTS_SUBSCRIPTIONS 表にデータを入力するため、/test/fixtures/subjects_subscriptions.yml ファイルを以下のように編集します。
リスト 20. subjects_subscriptions.yml
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
# Refer to /test/fixtures/subjects.yml for more information
# Subject ID 2 = Gardening
subscription160_gardening:
subscription_id: 160
subject_id: 2
# Subject ID 3 = Golf
subscription160_golf:
subscription_id: 160
subject_id: 3
|
上記では、160 というサブスクリプション ID を持つユーザーが 2 つのサブジェクト、Gardening (ガーデニング) と Golf (ゴルフ) をサブスクライブしていることになっています。
サブジェクトとサブスクリプションの関係をテストするということは、つまり SUBJECTS 表と SUBSCRIPTIONS 表の両方のデータにアクセスするとともに、結合表 SUBJECTS_SUBCRIPTIONS にもアクセスしなければならないということです。したがって、/test/unit/subjects_subscription_test.rb テストでは 3 つすべてのフィクスチャーをロードする必要があります。
リスト 21. フィクスチャー
class SubjectsSubscriptionTest < Test::Unit::TestCase
fixtures :subjects_subscriptions, :subjects, :subscriptions
[...]
end
|
このように、フィクスチャーは複数のテスト・ケースでテスト・データを共有する必要がある場合に極めて役立ちます。フィクスチャーについての詳細は、Ruby on Rails 資料に記載されている Class Fixtures を参照してください。
モックが役立つのは、外部システムへのアクセスを懸念することなくアプリケーションのコア機能をテストしたいという場合です。Team Room ではユーザー登録時に E メール・アドレスが正しい形式であることは検証しているものの、指定された E メール・アドレスが本当に存在するかどうかはまるでわかりません。E メール・アドレスが実際に有効なものであることを確認する唯一の方法は、指定された E メール・アドレスに E メールを送信することです。E メール・アドレスが有効ではなかったり、存在していなかったりすれば、E メール・プロバイダーからエラーが送られてくるからです。このようなサブスクリプション失敗の通知配信をテストする場合には、モックを使うことができます。
このテスト環境では、例えば E メール配信メソッドのモックを作成することができます。そこで、モックの作成対象となる配信メソッドを定義する email_provider.rb ファイルを /test/mocks/test ディレクトリーに作成します。モック・ファイルが配置されると、Rails はまず /test/mocks/test/email_provider.rb をロードし、それから /app/models/email_provider.rb の内容を調べます。
/test/mocks/test/email_provider.rb は以下のようになります。
リスト 22. フィクスチャー
require 'models/email_provider'
class EmailProvider
def deliver(request)
#Mock method
:success
end
end
|
モックを使用すれば、外部リソースにアクセスできなくても気にすることなく Team Room アプリケーションのコア機能のテストに専念することができます。
Rails アプリケーション・コントローラーのテストは、Web ブラウザーから送信されたすべてのリクエストがユーザー入力に基づいて期待通りに応答されると同時に、適切な状態変更が行われることを確実にすることを目的とします。そのためコントローラー内のアクションごとに、その特定のパス (URL) を使用するテスト・ケースが少なくとも 1 つは必要です。また、異なる状態をテストするために複数のテストが必要になる場合もあります (ユーザーが認証されている場合とそうでない場合でのアクションのアクセスなど)。
機能テストの一例として、ログイン・アクションと登録アクションに関係する UsersController のケースを検討します。関連する UsersControllerTest はモデル・クラスとコントローラー・クラスと併せて既に生成済みで、このテストにはセットアップとスタブ・メソッドの完全なテンプレートが含まれているので、実行パスを処理するのに必要なカスタマイズは最小限で済むことになります。
リスト 23. Users コントローラーのテスト
require File.dirname(__FILE__) + '/../test_helper'
require 'users_controller'
# Re-raise errors caught by the controller.
class UsersController; def rescue_action(e) raise e end; end
class UsersControllerTest < Test::Unit::TestCase
fixtures :users
def setup
@controller = UsersController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
@first_id = users(:first).id
end
[...]
end
|
必須メソッドである setup は、機能テストに常に必要な 3 つのインスタンス変数を初期化します。この 3 つのインスタンス変数とはつまり、テスト対象の controller、HTTP ヘッダー情報とともにユーザー入力が含まれる request、そしてテンプレートからレンダリングされたデータとステータス・コードを含むresponse です。
コントローラーのテストで重要な点は、このシナリオのテスト・データを提供する関連フィクスチャーです。そしてこの特定のコントローラーが、フィクスチャーの動的な側面をどのように使用するかを理解する手掛かりとなります。認証済みのユーザーを伴う上記のテスト・ケースでは、暗号化されたパスワードを計算するために USERS 表に有効なエントリーを設定する必要があります。暗号化パスワードを別途計算してフィクスチャーで直接使用することもできますが、ビューと部分ビューで行われているテンプレートの置換によっても同じように機能するため、タスクが簡単になります。
リスト 24. Users フィクスチャー
<% SALT = "tstsalt" unless defined?(SALT) >
first:
id: 141
usertype: usr
firstname: Homer
lastname: Simpson
extension: '9955'
email: homer@simpson.org
userid: homers
salt: <%= SALT %>
hash_passwd: <%= User.encrypt('secret' , SALT) %>
|
最初に行う test_index テスト・ケースは 2 つの異なるテスト・ケースに分ける必要があります。こうすると、ユーザーが認証された場合と認証されなかった場合のリクエストの処理をより正確に検証することができます。
リスト 25. Users コントローラーでのインデックス・アクションのテスト
def test_index_without_user
get :index
assert_redirected_to :action => "login"
assert_equal "Please sign-in" , flash[:notice]
end
def test_index_with_user
get :index, {}, {:user_id => users(:first).id}
assert_response 302
end
|
このコントローラーのインデックス・アクションでは、ユーザーが認証されていなければ常にログイン・ページを表示することになります。このアクションを実行するには、テスト・ケースでブラウザーからの GET リクエストをシミュレートする必要があります。ActionController::Integration::Session によって定義される get メソッドがHTTP リクエストを生成するために取得するものは、URL と、アクションによって渡された HTTP パラメーターを表すハッシュ (上記の場合は空)、そしてセッションを設定するためのパラメーターのハッシュです。これらが揃えば、あとは特定のテスト・ケースを呼び出すだけです。
リスト 26. Users コントローラー・テストの実行
D:\rails\teamroom>ruby test\functional\users_controller_test.rb -n test_index_with_user
Loaded suite test/functional/users_controller_test
Started
.
Finished in 0.719 seconds.
1 tests, 1 assertions, 0 failures, 0 errors
|
E メール通知をテストするには、単体テストおよび生成された E メールの内容の検証を行うだけでなく、機能テストも必要になります。機能テストによって、E メール通知が必要なときに常に送信されることが確実になるからです。そこで、第 2 回で Action Mailer をベースに実装した E メール通知コントローラーを基に、スタブによる機能テストで生成した SubscriptionMailerTest を使用し、通知動作に関係するモデルに対して既に作成されているフィクスチャーを利用することにします。
E メール通知とサブスクリプション確認の単体テストを行うには、メーラー・テスト用ドライブにローカル E メール配信用の ActionMailer を構成し (delivery_method = :test)、さらにモデル・フィクスチャーを使って通知および確認を呼び出すために必要なオブジェクトをセットアップする必要があります。
リスト 27. メーラー機能テストのセットアップ
class SubscriptionMailerTest < Test::Unit::TestCase
FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures'
CHARSET = "utf-8"
include ActionMailer::Quoting
fixtures :users
fixtures :subscriptions
fixtures :subjects
fixtures :documents
def setup
ActionMailer::Base.delivery_method = :test
ActionMailer::Base.perform_deliveries = true
ActionMailer::Base.deliveries = []
@user = users(:first)
@subscription = subscriptions(:one)
@doc = documents(:first)
@subject = subjects(:ruby_on_rails)
@subject.documents << @doc
@subject.subscriptions << @subscription
end
[...]
end
|
このテスト実装はメーラー・クラスを使用して E メールの内容を作成しますが (create_notify)、SMTP サーバーに実際に送信することはしません。代わりにアサーションを使用して、本文に含まれる特定のセクションをはじめとするメッセージ内の生成された部分 (受信者、送信者、タイムスタンプなど) を検証します。
リスト 28. E メール通知のテスト
def test_notify
response = SubscriptionMailer.create_notify(@doc)
assert_equal("TeamRoom new shared document notification", response.subject)
assert_equal("teamroom@developerWorks.ibm.com", response.from[0])
assert_equal(nil, response.to)
assert_equal("homer@simpson.org", response.bcc[0])
assert_in_delta(Time.now, response.date, 1.0)
assert_match(/A new document DB2onRails-logo.gif/, response.body)
assert_match(/subject: Ruby on Rails/, response.body)
end
|
サブスクリプション確認 E メールのテストでも同じような方法で、メッセージの内容を作成してから検証が行われます。さらに E メーラーの機能テストを行うということは、E メールを配布するのではなく、E メール・メッセージをメモリー内配列に追加する (ActionMailer::Base.deliveries = []) というコントローラーのテスト・ケースを意味します。これにより、送信済み E メールの数を検証するだけでなく、各メッセージの内容を検証することもできます。
デフォルトでは unit、functional、integration の外部のテスト・ディレクトリーのリストにパフォーマンス・テストのテンプレートが生成されることはありませんが、開発者がアプリケーションのパフォーマンス特性をいくつか評価したいという場合もあります。開発のあまりにも早い段階からパフォーマンスに重点を置くのは賢明ではありませんが、開発プロセスが終わりのサイクルに達するまでには、容量計画に対処するためにも、以降のサイクルを繰り返すなかで速度が落ちてきた場合にリグレッション・テストを確実に行えるようにするためにもパフォーマンス・テストを行うようお勧めします。
他のテスト・カテゴリーと併せてパフォーマンス・テストを実装する方法について簡単に説明するために、次のシナリオについて検討することにします。そのシナリオとは、パフォーマンス・テストを比較的大規模なエンタープライズ環境にデプロイした場合に、Team Room アプリケーションに非常に大きな負荷がかかってしまうかもしれないいうシナリオです。これまでと同じく、まずはテスト・データから取り掛かります。というのも、比較的大量のテスト・データを初期化する際に、パフォーマンス・テストのためにのみロードされる一連のフィクスチャーを使えるようにするためです。
リスト 29. 大規模なデータ・テスト・セットの場合の動的ユーザー・フィクスチャー
<% SALT = "tstsalt" unless defined?(SALT) %>
<% 200.upto(1200) do |i| %>user_<%= i %>:
id: <%= i %>
usertype: usr
firstname: New<%= i %>
lastname: One
extension: '9999'
userid: new<%= i %>
email: new<%= i %>@domain.net
salt: <%= SALT %>
hash_passwd: <%= User.encrypt('secret' , SALT) %>
<% end %>
|
このパフォーマンス・テストは通常の使用シナリオに基づくという前提で、極限の負荷をかける大規模なデータ・テスト・セットにまで拡張します。つまり、テスト・コントローラーは通常の機能テストで使用するものとかなり似ていますが、このテスト・ケースでは特定の点が誇張されているということです。ここで、ユーザー・コントローラーと極限の負荷でテストされるログイン・アクションについて考えてみると、テスト・データがロードされる場所 (self.fixture_path) を除けばテスト・ケースのセットアップは通常の機能テストとまったく同じになります。
リスト 30. ユーザー・ログイン・パフォーマンス・テストのセットアップ
class UserLoginTest < Test::Unit::TestCase
self.fixture_path = Pathname.new(File.dirname(__FILE__)).parent +
'fixtures' + 'performance'
fixtures :users
def setup
@controller = UsersController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
end
[...]
end
|
多数の同時ユーザーに対する Team Room の処理能力をテストするには、フィクスチャーに定義されたすべてのユーザーを同時にログインさせ、さらにはこのアクションに最小限の時間制限を設けるという方法があります。リスト 31 ではユーザー・ログインをループで実装するとともに、Ruby の標準ライブラリー・ベンチマークを使って時間の推定値を収集するためにロガーがオフになっていることを確認しています。
リスト 31. ログイン・アクションの際のユーザー・コントローラーのパフォーマンス・テスト
def test_1000_login
@controller.logger.silence do
user_count = 0
elapsed_time = Benchmark.realtime do
1200.downto(200) do |id|
user = users("user_#{id}")
post :login, :userid => user.userid, :password => 'secret'
user_count += 1
end
end
assert_equal 1001, user_count
assert elapsed_time < 10.0
end
end
|
さらに現実的なパフォーマンス・テストのシナリオとしては、マーケティング・レポートを支援する一部の XML クエリーが挙げられますが、これについてはこのようなアプリケーションを実動に移行させたいという読者の演習として残しておくことにします。このパフォーマンス・テストを実装する上で重要な点は、通常の機能テスト・ケースと結合テスト・ケースを大規模なテスト・データ・セットと極限の負荷と組み合わせて使用するということです。この手法によって、パフォーマンスの劣化を抑止するための実装を極めて簡単かつ効果的に行うことができます。
ディレクトリー構造は、rails teamroom コマンドを使って Team Room アプリケーションの作成を始めたときに生成されました。さらに重要なことには、Rails gem に組み込まれた一連のユーティリティーは「フック」されています。Rails gem は、他のすべてのコンポーネント (そのうち最もよく目にするコンポーネントは ActiveRecord と ActionView の 2 つです) のシームレスな統合を裏で調整する、単純かつ簡単な処理を行うコンポーネントですが、それと同時に、Rails gem は強力な Rake gem ヘルパーを使って、このフレームワークを使用するすべての Web アプリケーションにありがちな一連の問題に対処します。
make ユーティリティーに相当する Ruby の Rake は、その事前定義されたタスク (make ターゲットに相当) によってマイグレーション、スキーマのロード/ダンプ、Rails gems の更新/フリーズ、そして文書の作成を手早く簡単に行えるようにするだけでなく、テストも手早く簡単に行えるようにします。Team Room アプリケーションのルート・ディレクトリーで
rake --tasks
を実行すると、この信頼性の高い支援機能、rake によって提供されるすべての事前定義タスクが表示されます。これはすべて Team Room アプリケーションにあらかじめ組み込まれたもので、ディレクトリー構造が作成され、Rake ファイルが作成されると、一連の事前定義タスクが含まれる tasks/rails ライブラリー・パスが共有されます。
単純な rake test コマンドで、それまでに作成された単体テストと機能テストのすべてを並行して実行することや、開発サイクルの中でこれらのテストを容易に呼び出すことができます。カテゴリー別にテストを実行することも可能で、Rails アプリケーションの標準ディレクトリー構造により、test/unit パスに定義されたテスト全体を難なくロードすることができます (リスト 32 を参照)。
リスト 32. Team Room アプリケーションのすべての単体テストの実行
D:\rails\teamroom>rake test:units
(in D:/rails/teamroom)
D:/ruby/bin/ruby -Ilib;test
"D:/ruby/lib/ruby/gems/1.8/gems/rake-0.7.2/lib/rake/rake_test_loader.rb"
"test/unit/customer_info_test.rb" "test/unit/document_test.rb"
"test/unit/subjects_subscription_test.rb" "test/unit/subject_test.rb"
"test/unit/subscription_mailer_test.rb" "test/unit/subscription_test.rb"
"test/unit/user_test.rb" "test/unit/xml_content_test.rb"
Loaded suite D:/ruby/lib/ruby/gems/1.8/gems/rake-0.7.2/lib/rake/rake_test_loader
Started
..........
Finished in 11.553 seconds.
|
rake test:functionals を呼び出すと、同じように包括的なテストのロードが行われ、rake がこれらのテストの実行を繋ぎ合わせてセット全体を網羅します。
Rails アプリケーションの開発時には、予期しない結果やエラーが起こる可能性があります。最初にチェックすべきものは、/log ディレクトリー (この例では、d:\rails\teamroom\log) にあるログ・ファイルです。Rails は環境ごとのログとエラーを独自のログに書き込みます。開発環境の問題については development.log を、テスト環境の問題については test.log を調べてください。アプリケーション自体での Rails ログ・ファイルと問題診断に加え、DB2 のトレース・ユーティリティーとログも Rails アプリケーションの問題を診断する際に役立ちます。
連載第 1 回で説明したように、ibm_db ドライバーは、IBM Driver for ODBC (Open Database Connectivity) and CLI (Call Level Interface) を使用して IBM データ・サーバーに接続します。これはつまり、IBM データ・サーバーとのすべてのやりとりは IBM Driver for ODBC and CLI を介して行われるため、CLI トレースで取り込むことができるということです。CLI トレースは Ruby アプリケーションが DB2 Driver for ODBC and CLI ドライバーに対して行ったあらゆる API 呼び出しを取り込み、すべての入力パラメーター、そしてドライバーからアプリケーションへの戻り値をログに記録します。したがって CLI トレースは、入力値と出力値、そして裏で実行されている Rails フレームワークによって生成された実際の SQL 文の詳細を知る上で貴重な情報源となります。
CLI トレースを有効にする手順はインフォメーション・センターに記載されています。
CLI トレースは、アプリケーションによって正しい SQL 文が実行されていること、そしてデータベースから正しい値が返されていることを検証する貴重なツールです。Team Room アプリケーションではほとんどの SQL 文が Rails によって生成されるため、CLI トレースの出力を辿っていけば、図 2 に示した XML 文書をアップロードすることによって DB2 データベースに送信されたクエリーが明らかになります (図 2 を参照)。XML 文書をアップロードするには、以下のように 3 つの個別の表にデータを挿入する必要があります。
-
まず、コンテンツのタイプ、名前、プラットフォーム、サイズ、サブジェクト、ファイルをアップロードしたユーザーの ID、そして更新時刻と作成時刻を documents 表に挿入します。
リスト 33. CLI トレース: パート 1SQLExecDirect( hStmt=1:8 ) ---> Time elapsed - +1.844000E-003 seconds ( pszSqlStr="INSERT INTO documents (content_type, name, platform, size, updated_at, subject_id, user_id, created_at, data) VALUES('text/xml', 'CAN-Central.xml', 'Any', 125177, '2007-06-07 13:12:57', NULL, 100, '2007-06-07 13:12:49', NULL)", cbSqlStr=225 ) ( StmtOut="INSERT INTO documents (content_type, name, platform, size, updated_at, subject_id, user_id, created_at, data) VALUES(?, ?, ?, 125177, ?, NULL, 100, ?, NULL)" ) ( Package="SYSSH200 ", Section=11 ) sqlccsend( Handle - 84681200 ) sqlccsend( ulBytes - 349 ) sqlccsend( ) rc - 0, time elapsed - +1.991000E-003 sqlccrecv( timeout - +0.000000E+000 ) sqlccrecv( ulBytes - 188 ) - rc - 0, time elapsed - +2.471000E-003 ( Row=1, iPar=1, fCType=SQL_C_CHAR, rgbValue="text/xml" - x'746578742F786D6C', pcbValu... ( Row=1, iPar=2, fCType=SQL_C_CHAR, rgbValue="CAN-Central.xml" - x'43414E2D43656E74726... ( Row=1, iPar=3, fCType=SQL_C_CHAR, rgbValue="Any" - x'416E79', pcbValue=3, piIndicato... ( Row=1, iPar=4, fCType=SQL_C_CHAR, rgbValue="2007-06-07 13:12:57" - x'323030372D30362... ( Row=1, iPar=5, fCType=SQL_C_CHAR, rgbValue="2007-06-07 13:12:49" - x'323030372D30362... sqlccsend( Handle - 84681200 ) sqlccsend( ulBytes - 223 ) sqlccsend( ) rc - 0, time elapsed - +2.380000E-004 sqlccrecv( timeout - +0.000000E+000 ) sqlccrecv( ulBytes - 127 ) - rc - 0, time elapsed - +1.909000E-003 SQLExecDirect( ) <--- SQL_SUCCESS Time elapsed - +1.504370E-001 seconds ...
-
XML ファイルの名前と documents 表でそれに対応する ID、そして XML プレースホルダーを挿入します。
リスト 34. CLI トレース: パート 2SQLExecDirect( hStmt=1:8 ) ---> Time elapsed - +5.003000E-003 seconds ( pszSqlStr="INSERT INTO xml_contents (name, document_id, data) VALUES('CAN-Central.xml', 101, '<ibm>@@@IBMXML@@@</ibm>')", cbSqlStr=108 ) ( StmtOut="INSERT INTO xml_contents (name, document_id, data) VALUES(?, 101, ?)" ) ( Package="SYSSH200 ", Section=11 ) sqlccsend( Handle - 84681200 ) sqlccsend( ulBytes - 261 ) sqlccsend( ) rc - 0, time elapsed - +1.799000E-003 sqlccrecv( timeout - +0.000000E+000 ) sqlccrecv( ulBytes - 137 ) - rc - 0, time elapsed - +1.865000E-003 ( Row=1, iPar=1, fCType=SQL_C_CHAR, rgbValue="CAN-Central.xml" - x'43414E2D43656E747261... ( Row=1, iPar=2, fCType=SQL_C_CHAR, rgbValue="<ibm>@@@IBMXML@@@</ibm>" - x'3C69626D3E40... sqlccsend( Handle - 84681200 ) sqlccsend( ulBytes - 221 ) sqlccsend( ) rc - 0, time elapsed - +1.000000E-005 sqlccrecv( timeout - +0.000000E+000 ) sqlccrecv( ulBytes - 89 ) - rc - 0, time elapsed - +1.840000E-003 SQLExecDirect( ) <--- SQL_SUCCESS Time elapsed - +8.456800E-002 seconds ...
-
上記に続く update 文によって実際に XML データが挿入されます。
リスト 35. CLI トレース: パート 3SQLPrepare( hStmt=1:8 ) ---> Time elapsed - +1.861000E-003 seconds ( pszSqlStr="UPDATE xml_contents SET (data) = (?) WHERE id = 101", cbSqlStr=51 ) ( StmtOut="UPDATE xml_contents SET (data) = (?) WHERE id = 101" ) ( Package="SYSSH200 ", Section=11 ) sqlccsend( Handle - 84681200 ) sqlccsend( ulBytes - 244 ) sqlccsend( ) rc - 0, time elapsed - +1.000000E-005 sqlccrecv( timeout - +0.000000E+000 ) sqlccrecv( ulBytes - 120 ) - rc - 0, time elapsed - +1.923000E-003 SQLPrepare( ) <--- SQL_SUCCESS Time elapsed - +3.831300E-002 seconds ... SQLDescribeParam( hStmt=1:8, usPar=1, psSQLType= ... ---> Time elapsed - +2.315000E-003 seconds SQLDescribeParam( psSQLType=SQL_XML, puiParamDef=0, psScale=0, ... <--- SQL_SUCCESS Time elapsed - +2.457500E-002 seconds SQLBindParameter( hStmt=1:8, iPar=1, fParamType=SQL_PARAM_INPUT, fCType=SQL_C_BINARY, fSQLType=SQL_XML, cbColDef=0, ibScale=0, rgbValue= ... ---> Time elapsed - +2.225000E-003 seconds SQLBindParameter( ) <--- SQL_SUCCESS Time elapsed - +3.743500E-002 seconds SQLExecute( hStmt=1:8 ) ---> Time elapsed - +1.848000E-003 seconds E0D0A202020202020202020203C2F6974656D3E0D0A202020....., pcbValue=125177 ) sqlccsend( Handle - 84681200 ) sqlccsend( ulBytes - 61440 ) sqlccsend( ) rc - 0, time elapsed - +2.710000E-004 sqlccsend( Handle - 84681200 ) sqlccsend( ulBytes - 61440 ) sqlccsend( ) rc - 0, time elapsed - +2.120000E-004 sqlccsend( Handle - 84681200 ) sqlccsend( ulBytes - 2450 ) sqlccsend( ) rc - 0, time elapsed - +1.300000E-005 sqlccrecv( timeout - +0.000000E+000 ) sqlccrecv( ulBytes - 89 ) - rc - 0, time elapsed - +2.345000E-003 SQLExecute( ) <--- SQL_SUCCESS Time elapsed - +9.107600E-002 seconds ...
-
最後に、insert 文によって SUBJECTS 表にデータが適宜、設定されます。
リスト 36. CLI トレース: パート 4SQLExecDirect( hStmt=1:10 ) ---> Time elapsed - +2.166000E-003 seconds ( pszSqlStr="INSERT INTO subjects (name, size, tag, description) VALUES('Marketing', 1, 'sales', '@@@IBMTEXT@@@')", cbSqlStr=100 ) ( StmtOut="INSERT INTO subjects (name, size, tag, description) VALUES(?, 1, ?, ?)" ) ( Package="SYSSH200 ", Section=14 ) sqlccsend( Handle - 84681200 ) sqlccsend( ulBytes - 263 ) sqlccsend( ) rc - 0, time elapsed - +1.920000E-004 sqlccrecv( timeout - +0.000000E+000 ) sqlccrecv( ulBytes - 154 ) - rc - 0, time elapsed - +1.823000E-003 ( Row=1, iPar=1, fCType=SQL_C_CHAR, rgbValue="Marketing" - x'4D61726B6574696E67', ... ( Row=1, iPar=2, fCType=SQL_C_CHAR, rgbValue="sales" - x'73616C6573', pcbValue=5, ... ( Row=1, iPar=3, fCType=SQL_C_CHAR, rgbValue="@@@IBMTEXT@@@" - x'40404049424D5445 ... sqlccsend( Handle - 84681200 ) sqlccsend( ulBytes - 182 ) sqlccsend( ) rc - 0, time elapsed - +3.160000E-004 sqlccrecv( timeout - +0.000000E+000 ) sqlccrecv( ulBytes - 89 ) - rc - 0, time elapsed - +2.128700E-002 SQLExecDirect( ) <--- SQL_SUCCESS Time elapsed - +1.243580E-001 seconds
トレース可能なすべての内部 DB2 関数呼び出しを取り込む DB2 トレースは、DB2 が関わるアプリケーションの問題を調べるには欠かせないツールです。このトレースは、アプリケーション実行時の DB2 内部アクティビティーに関する情報を提供します。DB2 トレースには効率的に情報収集をできるようにするための、いくつかの特徴があります。
- トレースのオン、オフは動的に切り替えることが可能です。トレースを有効または無効にするためにアプリケーションを再起動する必要はありません。したがって、正確な障害点がわかっていれば、トレースをその障害の直前に有効にして関連する情報だけを収集することができます。
- DB2トレース情報はメモリーまたはディスクに保管することができます。
- トレース・マスクを適用して特定のコンポーネントだけをトレースすることができます。
DB2 トレースを有効にする手順については、インフォメーション・センターを参照してください。
Rails アプリケーションでの DB2 の問題のトラブルシューティングには、アプリケーションが常駐するクライアントで DB2 トレースと CLI トレースの両方を収集すると役に立ちます。
db2diag.log は、DB2 によって発生したエラーと一部の警告をログに記録します。この db2diag.log を調べると、アプリケーションの実行中に DB2 のエラーまたは警告がログに記録されたかどうかがわかります。ログに記録する情報の種類は、dbm cfg でデフォルトの 3 を他の値に設定することで、変更できます。
DB2 9® では db2diag 分析ツールを使って db2diag.log ファイルのフィルタリングとフォーマット設定を行うことができます。このツールでは例えば、特定のデータベースまたはタイムスタンプの値に関連するログ・エントリーを他のものからフィルタリングすることができます。db2diag ツールについての詳細は、インフォメーション・センターを参照してください。
- ibm_db Ruby アダプターとドライバーを使うには DB2 クライアント・システムが必要ですか? 必要です。連載「DB2 と Ruby on Rails」の第 1 回で説明したように、IBM_DB アダプター (ibm_db_adapter.rb) が直接の依存関係を持つ ibm_db Ruby ドライバーは、IBM Driver for ODBC and the CLI を使用して IBM データ・サーバーに接続します。そのため少なくとも IBM DB2 Driver for ODBC and CLI が必要になりますが、IBM_DB アダプターとサポートされるすべての IBM データ・サーバーとの接続を可能にするためには DB2 9 FP2 またはそれ以降のクライアント・パッケージ (CLI ドライバーが組み込まれています) で十分です。
- DB2 に対して Rails アプリケーションを実行しようとしたら、以下のエラーが表示されました。
SQL0954C: Not enough storage is available in the application heap to process the statement.第 1 回で説明したように、DB2 9 での Rails アプリケーションには 1024 以上の APPLHEAPSZ が必要です。APPLHEAPSZ をチェックするには、ご使用のデータベースに接続して構成パラメーターを取得してください。 - DB2 Connect は、IBM Ruby Driver を使って DB2 i5 または DB2 for z/OS サーバーにアクセスしなければならないのですか? その通りです。DB2 クライアントが DB2 i5 または DB2 z/OS サーバーに接続するには DB2 Connect が必要になります。IBM DB2 Driver for ODBC and CLI を使用する場合には、有効なライセンス・ファイルがドライバーのインストール・パスに含まれていなければなりません。
-
rake db:test:* コマンドを実行して開発でのテスト環境を複製しようとすると、
rake abortedエラーが表示されます。 database.yml ファイルを調べてください。テスト環境は、rails コマンドが生成するデフォルト構成に指定された database.yml の詳細に従ってセットアップされている必要があります。また、注 1 で述べた 2 つのファイルも修正してパッチを当ててください。 -
IBM_DB アダプターの最新バージョンで修正されているはずの問題が発生します。一方で gem list --local コマンドを実行すると IBM_DB アダプターの最新バージョンがインストールされていると表示されます。
<ruby_path>\lib\ruby\gems\1.8\gems\activerecord-1.15.3\lib\active_record\connection_adapters、または UNIX® での同様のパスに ibm_db_adapter.rb のコピーが含まれていないことを確認してください。
GEM_HOMEパス <ruby_path>\lib\ruby\gems\1.8\gems\ibm_db-<version>-mswin32\lib\active_record\connection_adapters (または UNIX での同様のパス) にインストールされた最新 IBM_DB gem に含まれる ibm_db_adapter.rb のコピーは 1 つでなければなりません。このファイルがRails 環境にロードされた唯一の IBM_DB アダプターになります。 -
今度の Rails 1.2.4 では、
config.connection_adaptersとRAILS_CONNECTION_ADAPTERSがなくなる予定です。したがって、第 1 回で説明したように Rails フレームワークの接続アダプター・リストに手動で「ibm_db」を登録する必要はなくなり、gem install ibm_db コマンドで IBM_DB アダプターをインストールすると、すぐに Rails 環境が検出してロードするようになります。
Rails フレームワークに組み込まれたテスト・サポートは、テストを簡単に行えるようにしてくれます。Rails アプリケーションそれぞれのテスト、開発、実動環境は config/database.yml ファイルに定義されるので、このファイルを使用して、さまざまな目的に合わせて異なるデータベースをセットアップすることができます。新規 Rails プロジェクトを作成すると、Rails により自動的にテスト・インフラストラクチャーが生成され、モデルとコントローラーを作成するごとに、対応するテスト・スタブが作成されます。単体テストでは Rails モデルのテストを行い、機能テストと結合テストでは、さらに上位レベルで Rails アプリケーションが設計どおりに確実に動作するようにテストを行います。また、フィクスチャーではテスト用のデータを指定することが可能で、さらにモック・オブジェクトを使えばネットワーク接続や外部システムとのアクセスを考えることなくコア・アプリケーションのテストに専念できます。Rails にはこれらの機能が組み込まれているため、テストする際に並外れて便利なフレームワークとなります。
| 内容 | ファイル名 | サイズ | ダウンロード形式 |
|---|---|---|---|
| Team room sample code | Teamroom3.zip | 10KB | HTTP |
学ぶために
- 「DB2 と Ruby on Rails、第 1 回: DB2 と Ruby on Rails の導入」(developerWorks、2007年5月) では、IBM_DB ドライバーをインストールするための Starter Toolkit for DB2 on Rails と各種方法、そして DB2 での Rails のマイグレーションについて紹介しています。
- 「DB2 と Ruby on Rails、第 2 回: Ruby on Rails を使用したDB2 と pureXML」(developerWorks、2007年6月) では、DB2 に備わった pureXML のネイティブ XML サポートと Ruby on Rails の組み合わせが、Web アプリケーション開発にとっていかに強力であるかを説明しています。
- 「Ruby on Rails and J2EE:Is there room for both?」(developerWorks、2005年7月) では、2 つの Web アプリケーション・フレームワーク、J2EE と Ruby on Rails を比較対照しています。
- 「境界を越える: アクティブ・レコードを探る」(developerWorks、2006年3月) では、Ruby on Rails の背後にあるパーシスタンス・エンジン、アクティブ・レコードについて詳しく説明しています。
- 「Crossing borders: What's the secret sauce in Ruby on Rails?」(developerWorks、2006年5月) では、Rails の優れた生産性を決定している理由を探り、Java コミュニティーで関心が高まることが期待される Rails に触発されたアイデアを取り上げています。
- 「An introduction to Ruby on Rails for DB2 developers」(developerWorks、2006年6月) は、Ruby on Rails をステップバイステップで紹介している入門記事です。
- 「境界を越える: Rails のマイグレーション」(developerWorks、2006年8月) では、Rails のマイグレーションを分かりやすく概説し、MySQL を使った Rails でのマイグレーションを紹介しています。
- 「Make Ruby on Rails easy with RadRails and Eclipse」(developerWorks、2006年9月) では、Ruby on Rails に対応した Eclipse ベースの開発ツールを紹介しています。
-
ActiveRecord 関連についての資料を参照してください。
- 「From DAD to annotated XML schema decomposition」(Mayank Pradhan 著、developerWorks、2006年4月) は、XML Extender 分解からアノテーション付き XML スキーマ分解へのマイグレーションについてのガイドです。
- 「Ruby on Rails and XML」(Daniel Wintschel 著、developerWorks、2007年4月) では、Ruby で XML データを操作する方法を解説しています。
- DB2 9 pureXML については、「DB2 9 pureXML ガイド」を参照してください。
-
テクノロジーのブックストアで、この技術やその他の技術に関する本を探してください。
-
DB2 for Linux, UNIX, and Windows に関する developerWorks の資料ページにアクセスしてください。ここには DB2 の手腕を磨くための記事とチュートリアル、そして他の資料へのリンクも記載されています。
- コミュニティー向け DB2 Express Edition の無料バージョン、 DB2 Express-C について調べてみてください。
製品や技術を入手するために
-
IBM 製品の評価版をダウンロードして、DB2®、Lotus®、Rational®、Tivoli®、および WebSphere® のアプリケーション開発ツールとミドルウェア製品を使ってみてください。
-
DB2 Enterprise 9 の無料の試用版をダウンロードしてください。
- DB2 を無料で使用するには、コミュニティー向け DB2 Express Edition の無料バージョン、DB2 Express-C をダウンロードしてください。DB2 Express Edtion と同じコア・データ機能を備えた DB2 Express-C は、アプリケーションをビルドしてデプロイするための安定した基盤になります。
-
DB2 Developer Workbench やその他の DB2 9 製品をダウンロードしてください。
-
IBM データベース対応 Rails Adapter/Driver を入手してください (rubyforge.org)。
-
IBM_DB adapter/driver gem およびプラグインをダウンロードしてください。
-
Starter Toolkit for DB2 on Rails をダウンロードしてください。
議論するために
-
ディスカッション・フォーラムに参加してください。
-
alphaWorks Forum for Starter Toolkit for DB2 on Rails にアクセスして関連情報を入手してください。
- RubyForge に関する質問、コメントは、RubyForge rubyibm Forum に投稿してください。
John Chun は、アプリケーション開発およびツールの分野で活躍する DB2 Advanced Support チームのスペシャリストです。IBM DBT Toronto Lab でこれまで 7 年間、Java、C、C++、Perl、REXX、C# をはじめとする各種言語での DB2 アプリケーション問題の解決に取り組んできました。DB2 CLI および OLEDB ドライバー、そして .NET データ・プロバイダー関連の多数のプロジェクトにも参加しています。彼は DB2 認定ソリューション・エキスパート、認定 Websphere アドミニストレーターでもあります。
Alex Pitigoi は、IBM Toronto Lab の顧問ソフトウェア・エンジニアです。1998年以来、Web 技術とデータベース管理を専門に、情報管理の分野でのさまざまなソフトウェア開発プロジェクトに携わっています。最近では、SQLModel プロジェクトの開発を指揮しました。この開発は現在、Eclipse Data Tools プロジェクトならびに複数の IBM データ・サーバーで、データベース管理 Web ツールの全体的アーキテクチャーに組み込まれています。彼は DB2 Satellite Administration Center、IBM Express Runtime にも取り組んでおり、DB2 を対象とした最初の Web Tools セットの開発も主導しています。現在重点的に取り組んでいるのは、新しいオープン・ソース技術 (Ruby、Python、PHP) へのIBM データ・サーバー対応化です。
Christine Law は、IBM Toronto Lab のシニア DB2 スペシャリスト兼 IBM 認定エキスパートです。JDBC、SQLJ、ストアード・プロシージャー、そして組み込みSQL を専門とする彼女は、さまざまなプログラミング言語とスクリプト言語を使った Linux、UNIX、Windows プラットフォームでの広範なアプリケーション開発経験を持っています。最近では、AJAXや Ruby などのオープン・ソース技術にも関心を寄せています。
Naomi Ngan は 2000年、カナダの University of Toronto でコンピューター・サイエンスと統計学の優等卒業学位を終了しました。卒業と同時に IBM に入社した彼女は、アプリケーション開発環境における IBM DB2 RDBMS 製品の欠点および問題の解決を担当しました。約 4 年間 IBM に在籍した後は UCSF の Ernest Gallo Clinic and Research Center に移り、バイオインフォマティクス・ソフトウェアの開発に携わっています。これには、Linux および Windows プラットフォームの XML 環境内でのデータベース・オブジェクト、JSP、Java スタンドアロン・アプリケーション、およびストアード・プロシージャーの設計と開発も含まれます。現在 Autonomy Corporation のシニア・ソフトウェア・エンジニアとして取り組んでいるのは J2EE エンタープライズ・ソフトウェアの開発です。DB2 のアプリケーションおよびツールに関する深い知識を持つ彼女は、DB2、XML、WebSphere、Java/J2EE の分野で数々の IBM および Sun 開発者認定を取得しています。