ビヘイビア駆動とかよく分からないけど、とりあえずRSpec書きながらプロシージャを作ってみる #1

とりあえず簡単なプロシージャをRSpec書きながら作ってみようと思います。

どんなの作るん?

PROCEDURE get_message( iv_message_code IN Messages.message_code%TYPE,
                       iv_token1 IN Messages.token1%TYPE,
            iv_token2 IN Messages.token2%TYPE,
            iv_token3 IN Messages.token3%TYPE,
            iv_token4 IN Messages.token4%TYPE,
            iv_token5 IN Messages.token5%TYPE,
            ov_message OUT VARCHAR2 );

iv_message_codeにメッセージコードを入力すると、対応したメッセージ文字列が返ってくるようなプロシージャです。テーブルを以下のように設定しておき

message_code message token1 token2 token3 token4 token5
MES100000 私の名前は &NAME です。 &NAME
get_message( iv_message_code => 'MES10000',
             iv_token1 => 'もっこす',
             ov_message => lv_message )

てな感じでプロシージャを実行すれば「私の名前は もっこす です。」とlv_messageに突っ込まれるイメージです。簡単すぎてすんません。。

とりあえずRSpec書いてみるか(ノープラン)

#
# messagesテーブルに保存されたメッセージを返すPL/SQLプログラムを
# RSpec書きながら作ってみるテスト
#
require 'rubygems'
require 'spec'
require 'oci8'
#
# テスト対象のPL/SQLプロシージャ
# (こんな感じのプロシージャ作る)
# PROCEDURE get_message( iv_message_code IN Messages.message_code%TYPE,
#                        iv_token1 IN Messages.token1%TYPE,
#             iv_token2 IN Messages.token2%TYPE,
#             iv_token3 IN Messages.token3%TYPE,
#             iv_token4 IN Messages.token4%TYPE,
#             iv_token5 IN Messages.token5%TYPE,
#             ov_message OUT VARCHAR2 );
#
target_plsql = <<-PLSQL
BEGIN
  get_message(:iv_message_code,
              :iv_token1,
              :iv_token2,
              :iv_token3,
              :iv_token4,
              :iv_token5,
              :ov_message);
END;
PLSQL
#
# データベース接続用変数
conn = nil
#
describe "トークンを指定せずにメッセージを取得するとき" do
	before(:all) do
		# テスト前準備 apxe/apxe@xeでデータベースへ接続
		conn = OCI8.new('apxe','apxe','xe')
	end

	after(:all) do
		# データベースからログオフ
		conn.logoff
	end
	
	it "(1) SELECT message FROM Messages WHERE message_code = 'MES000000'で「正常終了しました。」というメッセージを取得できる" do
		cursor = conn.exec("SELECT message FROM Messages WHERE message_code = 'MES000000'")
		cursor.fetch.should == ["正常終了しました。"]
	end

	it "(2) 「MES000000」を指定すると「正常終了しました。」というメッセージを取得" do
		cursor = conn.parse(target_plsql)
		cursor.bind_param(':iv_message_code', 'MES000000')
		cursor.bind_param(':iv_token1', '')
		cursor.bind_param(':iv_token2', '')
		cursor.bind_param(':iv_token3', '')
		cursor.bind_param(':iv_token4', '')
		cursor.bind_param(':iv_token5', '')
		cursor.bind_param(':ov_message', nil, String, 2000)
		cursor.exec
		cursor[':ov_message'].should == "正常終了しました。"
	end
end

既にデータベースにMessagesというテーブルを作成し、一つメッセージを登録してあるので(1)のテストは成功します。でも、まだプロシージャを作っていないので(2)のテストは下記のようにコケます。

トークンを指定せずにメッセージを取得するとき
- (1) SELECT message FROM Messages WHERE message_code = 'MES000000'で「正常終了しました。」というメッセージを取得できる
- (2) 「MES000000」を指定すると「正常終了しました。」というメッセージを取得 (ERROR - 1)

1)
OCIError in 'トークンを指定せずにメッセージを取得するとき (2) 「MES000000」を指定すると「正常終了しました。」というメッセージを取得'
ORA-06550: 行2、列3:
PLS-00201: 識別子GET_MESSAGEを宣言してください。
ORA-06550: 行2、列3:
PL/SQL: Statement ignored
stmt.c:539:in oci8lib.so
/Library/Ruby/Site/1.8/oci8.rb:759:in `exec'
/Library/Ruby/Site/1.8/oci8.rb:142:in `do_ocicall'
/Library/Ruby/Site/1.8/oci8.rb:759:in `exec'
./get_message_spec.rb:60:

Finished in 0.134598 seconds

2 examples, 1 failure

(1)のテストはdescribeの文章的には無い方がよさげですが、そもそもデータベースにテストデータ入ってるんかいという確認が欲しかったので付けました。

そういうわけで、(2)のテストを成功させるべくプロシージャを書いてみましょう。

プロシージャを書く

テストを成功させるために最小限のプロシージャを書きます。

CREATE OR REPLACE
PROCEDURE GET_MESSAGE(
  iv_message_code IN Messages.message_code%TYPE,
  iv_token1 IN Messages.token1%TYPE,
  iv_token2 IN Messages.token2%TYPE,
  iv_token3 IN Messages.token3%TYPE,
  iv_token4 IN Messages.token4%TYPE,
  iv_token5 IN Messages.token5%TYPE,
  ov_message OUT VARCHAR2 )
AS
  lv_ret_message VARCHAR2(2000);
BEGIN
  SELECT  message INTO lv_ret_message
  FROM    Messages
  WHERE   message_code = iv_message_code;
  
  -- OUT変数にMessagesから取得した文字列を代入
  ov_message := lv_ret_message;
END GET_MESSAGE;

そんでもってspecを実行!

pasta:get_message mahm$ spec -c -fs get_message_spec.rb 

トークンを指定せずにメッセージを取得するとき
- (1) SELECT message FROM Messages WHERE message_code = 'MES000000'で「正常終了しました。」というメッセージを取得できる
- (2) 「MES000000」を指定すると「正常終了しました。」というメッセージを取得

Finished in 0.077543 seconds

2 examples, 0 failures

おおー、通ってる。って、そりゃそうだろ。。

ソースコードのせいでエントリが長くなってきたので、続きは次のエントリで。今度はエラーハンドリングでも実装してみますか。

続き:ビヘイビア駆動とかよく分からないけど、とりあえずRSpec書きながらプロシージャを作ってみる #2 - ランバダ