15
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Rspecでinitializeでのインスタンス変数テストではまったこと

Posted at

例えばこんなクラスがあったとして、

sample01.rb
class Sample01

  def initialize
    @data = {name: "tanaka", age: 30}
    @name = _get_name
    @age = _get_age
  end

  def run
    puts "私の名前は#{@name}(#{@age}歳)です"
  end

  private

  def _get_name
    @data[:name]
  end

  def _get_age
    @data[:age]
  end
end

以下のようにインスタンス変数 data に test_data を設定し、

sample01_spec.rb
require './sample01'

describe Sample01 do
  let(:instance) { described_class.new }

  let(:test_data) { {name:'test', age: 99} }

  before :each do
    # インスタンス変数 data に test_data を設定
    instance.instance_variable_set(:@data, test_data)
  end

  describe '.initialize' do
    subject { instance.send('initialize') }

    it 'インスタンス変数が正しく設定されていること' do
      expect(instance.instance_variable_get(:@name)).to eq 'test'
      expect(instance.instance_variable_get(:@age)).to eq 99
   end
  end
end

インスタンス変数 name と age に任意の値が設定されているかをテストしても、値はうまく設定されずテスト失敗となる。

$ bundle exec rspec sample01_spec.rb 
F

Failures:

  1) Sample01.initialize インスタンス変数が正しく設定されていること
     Failure/Error: expect(instance.instance_variable_get(:@name)).to eq 'test'
       
       expected: "test"
            got: "tanaka"
       
       (compared using ==)
     # ./sample01_spec.rb:17:in `block (3 levels) in <top (required)>'

Finished in 0.02069 seconds (files took 0.15206 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./sample01_spec.rb:15 # Sample01.initialize インスタンス変数が正しく設定されていること

実行される処理順として、

  • instance.instance_variable_set(:@data, test_data) の箇所でまず Sample01 の initializeが呼ばれ、

  • instance.instance_variable_set(:@data, test_data) の箇所で実際にインスタンス変数 data に test_data が設定され、

  • expect(instance.instance_variable_get(:@name)).to eq 'test' で 設定された値がイコールとなる

想定のはずが、@name の値は tanaka のままとなっている。。。

代替案として、initialize で設定していたインスタンス変数 name と age を runメソッドに移動し、

sample01.rb
class Sample01

  def initialize
    @data = {name: "tanaka", age: 30}
    # run に移動
    # @name = _get_name
    # @age = _get_age
  end

  def run
    @name = _get_name
    @age = _get_age
    puts "私の名前は#{@name}(#{@age}歳)です"
  end

  private

  def _get_name
    @data[:name]
  end

  def _get_age
    @data[:age]
  end
end

同様のテストを run メソッドに対し行うことでとりあえず解決した。

sample01_spec.rb
require './sample01'

describe Sample01 do
  let(:instance) { described_class.new }

  let(:data) { {name:'test', age: 99} }

  before :each do
    instance.instance_variable_set(:@data, data)
  end

  describe '#run' do
    subject { instance.run }

    it 'インスタンス変数が正しく設定されていること' do
      subject
      expect(instance.instance_variable_get(:@name)).to eq 'test'
      expect(instance.instance_variable_get(:@age)).to eq 99
   end
  end
end

テスト結果

$ bundle exec rspec sample01_spec.rb 
私の名前はtest(99歳)です
.

Finished in 0.00546 seconds (files took 0.15378 seconds to load)
1 example, 0 failures
15
18
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?