mruby-mtestでngx_mrubyやmod_mrubyで使うmrubyのテストコードを書く


はじめに

こんにちは。 GMOペパボの久米です。 今回はngx_mrubymod_mrubyで動作させるmrubyスクリプトのテストコードをiij/mruby-mtestを使って書いていきます。 通常この場合のmrubyスクリプトはngx_mruby/mod_mruby上で動作しますが、今回はmrubyを単体でビルドして生成されたバイナリを使って動作させます。

環境構築

mrubyをgit cloneする
cd /usr/local/src
git clone https://github.com/mruby/mruby.git
cd mruby
ビルドするmgemを設定する
mv build_config.rb build_config.rb.org
vi build_config.rb

こちらに必要なmgemを設定します。 今回は以下のようにしました。

MRuby::Build.new do |conf|

  toolchain :gcc

  conf.gembox 'full-core'

  conf.gem :github => 'iij/mruby-io'
  conf.gem :github => 'iij/mruby-env'
  conf.gem :github => 'iij/mruby-dir'
  conf.gem :github => 'iij/mruby-digest'
  conf.gem :github => 'iij/mruby-process'
  conf.gem :github => 'iij/mruby-pack'
  conf.gem :github => 'iij/mruby-socket'
  conf.gem :github => 'matsumoto-r/mruby-sleep'
  conf.gem :github => 'matsumoto-r/mruby-userdata'
  conf.gem :github => 'matsumoto-r/mruby-uname'
  conf.gem :github => 'matsumoto-r/mruby-mutex'
  conf.gem :github => 'matsumoto-r/mruby-cache'
  # 必要に応じてここにmgemを追記する。

  conf.gem :github => 'iij/mruby-mtest'
end

“conf.gem :github => ‘iij/mruby-mtest’” と書いているのがテスト用のmgemです。

ビルドする
rake
パスの通った場所に生成されたmrubyのバイナリを配置する
cp -p mruby/bin/mruby /usr/local/bin/

動作確認

mruby --version

以下が表示される

mruby 1.2.0 (2015-11-17)

テストコードを実装するサンプルプログラムを用意する。

mruby.rb
#!mruby

# 本番用コード
class SampleClass
  def initialize(request)
    @r = request
  end

  def get_filename
    @r.filename
  end

  def get_uri
    @r.uri
  end
end

このSampleClassはhttpリクエストを受け取り、その内容を出力するためのメソッドが実装されているものです。

テストコードを実装する

上記コードに対して、テスト時の処理を以下のように追記する。 “# —” で囲っている部分がその箇所です。

#!mruby

# -----------------------------------
# テスト用の初期化処理
if Object.const_defined?(:MTest)
  class Apache
    class Request
	  attr_accessor :filename, :uri
	end
  end
end
# -----------------------------------

# 本番用コード
class SampleClass
  def initialize(request)
    @r = request
  end

  def get_filename
    @r.filename
  end

  def get_uri
    @r.uri
  end
end

# -----------------------------------
# テストコード

# テスト環境であれば実行
if Object.const_defined?(:MTest)
  class TestSampleClass < MTest::Unit::TestCase
    def setup
  	  @filename = "/var/www/html/test.php"
  	  @uri = "http://127.0.0.1/test.php"

  	  @request = Apache::Request.new
  	  @request.filename = @filename
  	  @request.uri = @uri
  	  @s = SampleClass.new @request
  	end

  	def test_get_filename
  	  str = @s.get_filename
  	  assert_equal(@filename, str)
  	end

  	def test_get_uri
  	  str = @s.get_uri
  	  assert_equal(@uri, str)
  	end
  end
  MTest::Unit.new.run
end
# -----------------------------------
  • “if Object.const_defined?(:MTest)” の意味は、mrubyにmruby-mtestがビルドされているかを判断させています。mruby-mtestがビルドされているときのみ処理が実行されるため本番の環境でmruby-mtestを含めなければ本番で実行されることはありません。

  • 今回作ったmrubyにはmod_mrubyやngx_mrubyで用意されているライブラリを含めてビルドしていないため “テスト用の初期化処理” でテストで使うクラスを実装しています。

    • もちろん、mrubyのビルド時にmod_mrubyやngx_mrubyのライブラリを “build_config.rb” 内で読み込ませれば必要ないです。
  • “def setup” はテスト実行時に最初に実行される処理を記述します。今回はテストで使用するhttpリクエストを手動で作成しています。

  • “assert_equal(@filename, str)” は “str” が “@filename” と同じであるべきとして定義しています。これに違反した場合はテストが失敗するということになります。

  • “MTest::Unit.new.run” 最後にこれを実行してテストを行います。

テストを実行してみる

mruby mruby.rb

実行結果

Finished tests in 0.000592s, 3378.3784 tests/s, 3378.3784 assertions/s.

2 tests, 2 assertions, 0 failures, 0 errors, 0 skips

これでmrubyもテストできるようになりました!

mruby  ci