2012-01-27 63 views
41

給定一個包含幾個實例變量和一些方法的類。一些實例變量可通過attr_readerattr_accessor訪問。因此其他人是私人的。
一些私有實例變量在其中一個實例方法中被設置並在另一個方法中讀取/使用。如何設置方法測試中使用的私有實例變量?

爲了測試我正在使用RSpec。由於我對Ruby還是個新手,並且想要把所有的東西都搞定,所以我將測試定義得相當細緻。因此,對於每個實例方法,我都有一個describe塊,它們本身被劃分爲contextit的子集。一般環境前提條件定義爲before

但是,當測試其中一個方法,即利用但不設置其中一個私有變量時,我需要調用另一個方法,即設置此變量。這看起來相當超重,對我來說不是模塊化的。

有沒有辦法強制一個私人實例變量到某個值。類似於「取出」的私有實例變量的值,其值爲Object::instance_eval(:var)

回答

78

正如你在你的問題回答設置實例變量的最簡單的方法是用instance_eval方法:

obj.instance_eval('@a = 1') 

另一種方法是使用instance_variable_set:

obj.instance_variable_set(:@a, 1) 

但我不會推薦這樣做我n你的規格。規格都是關於對象的測試行爲,通過使用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) 
+0

還沒有想過存根訪問器呢。可能會使我的很多測試數據(一些文本文件,應該由我的程序檢測和解析)過時。看起來很不錯。謝謝:) – 2012-01-27 19:18:35

+0

只是爲了澄清,在你的答案中,你是否聲稱'instance_eval'打破了類封裝或者'instance_variable_set'呢? – Seanny123 2013-12-16 08:28:41

+0

@ Seanny123'instance_eval'和'instance_variable_set'都修改了實例私有的內部狀態,不應該在對象之外進行修改。 – 2013-12-16 10:25:59

7

使用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 
+0

感謝的爲。我知道這很容易。 :) – 2012-01-27 19:03:23