52

Given a class with a couple of instance variables and some methods. Some instance variables are set accessible via attr_reader and attr_accessor. Thus the others are private.
Some of the private instance variables get set within one of the instance methods and read/utilized within another method.

For testing I'm using RSpec. As I'm still new to Ruby and want to get all things right, I defined my tests being rather fine-grained. Thus I've got one describe block for each instance method, which themselves are partitioned into a subset of contexts and its. General environmental preconditions are defined with before.

However, when testing one of the methods, which is utilizing but not setting one of the private variables, I need to call the other method, which is setting this variable. This seems rather overweight and not modular for me.

Is there a way of forcing a private instance variable to a certain value. Similar to "ripping out" the value of a private instance variable with 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 回答