2012-01-27 4 views
41

Учитывая класс с несколькими переменными экземпляра и некоторыми методами. Некоторые переменные экземпляра устанавливаются через attr_reader и attr_accessor. Таким образом, другие являются частными.
Некоторые из переменных частного экземпляра устанавливаются в одном из методов экземпляра и считываются/используются в рамках другого метода.Как установить частную переменную экземпляра, используемую в тесте метода?

Для тестирования я использую RSpec. Поскольку я еще новичок в Ruby и хочу, чтобы все было правильно, я определил, что мои тесты довольно мелкозернистые. Таким образом, у меня есть один блок describe для каждого метода экземпляра, который сам разбит на подмножество context s и it s. Общие предварительные условия окружающей среды определяются с помощью before.

Однако при тестировании одного из методов, который использует, но не устанавливает одну из частных переменных, мне нужно вызвать другой метод, который устанавливает эту переменную. Это кажется избыточным весом, а не модульным для меня.

Есть ли способ принуждения переменной частного экземпляра к определенному значению. Подобно «, вырывая» значение переменной частного экземпляра с Object::instance_eval(:var).

ответ

78

Как вы ответили на свой вопрос, самый простой способ установить переменную экземпляра является с instance_eval метода:

obj.instance_eval('@a = 1') 

Другой способ заключается в использовании instance_variable_set:

obj.instance_variable_set(:@a, 1) 

Но я бы не рекомендовал это делать i 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

Еще не задумывались о том, чтобы получить доступ к аксессуарам. Вероятно, я сделал бы много моих тестовых данных (некоторые текстовые файлы, которые должны быть обнаружены и проанализированы моей программой) устарели. Кажется приятным способом. Спасибо :) –

+0

Просто чтобы пояснить, в вашем ответе, вы утверждаете, что 'instance_eval' ломает инкапсуляцию класса или что' instance_variable_set' делает? – Seanny123

+0

@ Seanny123 Оба экземпляра 'instance_eval' и' instance_variable_set' изменяют внутреннее состояние, которое является приватным экземпляру и не должно быть изменено вне объекта. –

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

Спасибо за это. Я знал, что это легко. :) –

Смежные вопросы