web-dev-qa-db-fra.com

Comment définir la variable d'instance privée utilisée dans un test de méthode?

É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 contexts et its. 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).

45
Torbjörn

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)
84

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
8
robbrit

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
0
Chris