2012-01-27 13 views
41

Podano klasę z kilkoma zmiennymi instancji i kilkoma metodami. Niektóre zmienne instancji są dostępne za pośrednictwem attr_reader i attr_accessor. Tak więc pozostałe są prywatne.
Niektóre prywatne instancyjne zmienne są ustawiane w ramach jednej z metod instancji i odczytywane/wykorzystywane w ramach innej metody.Jak ustawić prywatną instancję zmienną używaną w teście metody?

Do testowania używam RSpec. Ponieważ wciąż jestem nowicjuszem w Ruby i chcę wszystko naprawić, zdałem sobie sprawę, że moje testy są raczej drobiazgowe. Tak więc mam jeden blok describe dla każdej metody instancji, które same są podzielone na podzbiory z context s i it s. Ogólne warunki środowiskowe definiuje się przy pomocy before.

Jednak podczas testowania jednej z metod, która wykorzystuje, ale nie ustawia jednej ze zmiennych prywatnych, należy wywołać inną metodę, która ustawia tę zmienną. Wydaje mi się, że jest to raczej nadwaga i nie jest ona modułowa.

Czy istnieje sposób na wymuszenie zmiennej instancji prywatnej na pewną wartość. Podobne do "zgrywanie" wartość prywatnej zmiennej instancji z Object::instance_eval(:var).

Odpowiedz

78

Jak można odpowiedzieć na pytanie najprostszy sposób, aby ustawić zmienną instancji jest z instance_eval metody:

obj.instance_eval('@a = 1') 

Innym sposobem jest użycie instance_variable_set:

obj.instance_variable_set(:@a, 1) 

Ale nie poleciłbym tego zrobić n twoja specyfikacja. Specyfikacja polega na testowaniu zachowania obiektu, a zachowanie testowe poprzez złamanie klasy enkapsulacji za pomocą instance_eval spowoduje, że testy będą bardziej kruche i zależą od implementacji.

Alternatywne podejście do obiektu izolacji państwa jest skrótową metody dostępowe:

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

Jeszcze nie myślałem o stublowych akcesoriach. Prawdopodobnie sprawiłoby, że wiele moich danych testowych (niektóre pliki tekstowe, które powinny zostać wykryte i przeanalizowane przez mój program) były przestarzałe. Wydaje się fajny sposób. Dzięki :) –

+0

W celu wyjaśnienia, w twojej odpowiedzi, twierdzisz, że 'instance_eval' łamie enkapsulację klasy lub że' instance_variable_set' również działa? – Seanny123

+0

@ Seanny123 Zarówno 'instance_eval' oraz' instance_variable_set' modyfikują wewnętrzny stan, który jest prywatny dla instancji i nie powinien być modyfikowany poza obiektem. –

7

Zastosowanie 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

Dziękuję za to. Wiedziałem, że to łatwe. :) –