Étant donné une classe avec quelques variables d'instance et certaines méthodes. Certaines variables d'instance sont définies comme accessibles via attr_reader
Et attr_accessor
. Les autres sont donc privés.
Certaines des variables d'instance privées sont définies dans l'une des méthodes d'instance et lues/utilisées dans une autre méthode.
Pour les tests, j'utilise RSpec. Comme je suis encore nouveau à Ruby et que je veux que tout soit bien, j'ai défini mes tests comme étant assez fins. J'ai donc un bloc describe
pour chaque méthode d'instance, qui sont eux-mêmes partitionnés en un sous-ensemble de context
s et it
s. Les conditions environnementales générales sont définies avec before
.
Cependant, lorsque je teste l'une des méthodes, qui utilise mais ne définit pas l'une des variables privées, je dois appeler l'autre méthode, qui définit cette variable. Cela me semble plutôt en surpoids et pas modulaire.
Existe-t-il un moyen de forcer une variable d'instance privée à une certaine valeur. Similaire à "ripping out" la valeur d'une variable d'instance privée avec Object::instance_eval(:var)
.
Comme vous l'avez répondu dans votre question, le moyen le plus simple de définir une variable d'instance est de instance_eval
méthode:
obj.instance_eval('@a = 1')
Une autre façon consiste à utiliser instance_variable_set:
obj.instance_variable_set(:@a, 1)
Mais je ne recommanderais pas de le faire dans vos spécifications. Les spécifications concernent le test du comportement d'un objet et le test du comportement en cassant l'encapsulation de classe avec instance_eval
rendra vos tests plus fragiles et dépendants de l'implémentation.
Une approche alternative à l'isolement de l'état des objets consiste à remplacer les méthodes d'accesseur:
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)
Utilisation 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
Je viens de le résoudre en créant un enfant et en ajoutant un accesseur:
class HasSecrets
@muahaha
end
class TestMe < HasSecrets
attr_accessor(:muahaha)
end
def test_stuff
pwned = TestMe.new()
pwned.muahaha = 'calc.exe'
end