52

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

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

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

プライベートインスタンス変数を特定の値に強制する方法はありますか?。を使用してプライベートインスタンス変数の値を「リッピング」するのと同様Object::instance_eval(:var)です。

4

3 に答える 3

95

あなたがあなたの質問で答えたように、インスタンス変数を設定する最も簡単な方法は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)
于 2012-01-27T19:06:14.623 に答える
12

使用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
于 2012-01-27T19:01:58.860 に答える
0

子を作成し、アクセサを追加することで解決しました。

class HasSecrets
  @muahaha
end

class TestMe < HasSecrets
  attr_accessor(:muahaha)
end

def test_stuff
  pwned = TestMe.new()
  pwned.muahaha = 'calc.exe'
end
于 2019-04-04T13:50:36.837 に答える