web-dev-qa-db-ja.com

メソッドテスト内で使用されるプライベートインスタンス変数を設定する方法

いくつかのインスタンス変数といくつかのメソッドを持つクラスを考えます。一部のインスタンス変数は、_attr_reader_および_attr_accessor_を介してアクセス可能に設定されます。したがって、他はプライベートです。
一部のプライベートインスタンス変数は、いずれかのインスタンスメソッド内で設定され、別のメソッド内で読み取り/利用されます。

テストには、RSpecを使用しています。 Rubyが初めてで、すべてを正しくしたいので、テストをかなりきめ細かく定義しました。したがって、それぞれに1つのdescribeブロックがありますインスタンスメソッドは、それ自体がcontextsとitsのサブセットに分割されます。一般的な環境の前提条件は、beforeで定義されます。

ただし、プライベート変数の1つを使用するが設定しないメソッドの1つをテストする場合、この変数を設定する他のメソッドを呼び出す必要があります。これはかなり太りすぎで、私にとってはモジュール式ではありません。

プライベートインスタンス変数を特定の値に強制する方法はありますか。 「ripping outObject::instance_eval(:var)を使用したプライベートインスタンス変数の値」に似ています。

45
Torbjörn

質問で答えたように、インスタンス変数を設定する最も簡単な方法は、instance_evalメソッドを使用することです。

obj.instance_eval('@a = 1')

別の方法は、instance_variable_setを使用することです。

obj.instance_variable_set(:@a, 1)

ただし、仕様でこれを行うことはお勧めしません。仕様は、オブジェクトの動作のテストに関するものであり、instance_evalでクラスのカプセル化を解除することで動作をテストすると、テストが脆弱になり、実装に依存します。

オブジェクト状態分離の代替アプローチは、アクセサメソッドをスタブ化することです。

class UnderTest
  attr_accessor :a

  def test_this
    do_something if a == 1
  end
end

#in your test
under_test = UnderTest.new
under_test.stub(:a).and_return(1)
84

つかいます instance_variable_set

class SomeClass
  attr_reader :hello
  def initialize
    @hello = 5
  end
  # ...
end

a = SomeClass.new
a.hello    # => 5

a.instance_variable_set("@hello", 7)
a.hello    # => 7
8
robbrit

私はちょうど子を作成し、アクセサーを追加することでそれを解決しました:

class HasSecrets
  @muahaha
end

class TestMe < HasSecrets
  attr_accessor(:muahaha)
end

def test_stuff
  pwned = TestMe.new()
  pwned.muahaha = 'calc.exe'
end
0
Chris