Testing RSpec Class Variables

I am testing a class instance variable (and setters) in stone using RSpec. I need to check the following:

  • The correct default value is provided if the setter is never used.
  • This variable can be successfully updated via setters.

Obviously, there is a problem with the execution order. If I change values โ€‹โ€‹using setters, I lose memory of what was by default. I can save it in a variable before the setter test, and then reset the value at the end, but this only protects me if all the setter tests follow the same practice.

What is the best way to check the default value for a variable?

Here is a simple example:

class Foo class << self attr_accessor :items end @items = %w(foo bar baz) # Set the default ... end describe Foo do it "should have a default" do Foo.items.should eq(%w(foo bar baz)) end it "should allow items to be added" do Foo.items << "kittens" Foo.items.include?("kittens").should eq(true) end end 
+7
source share
3 answers
 class Foo DEFAULT_ITEMS = %w(foo bar baz) class << self attr_accessor :items end @items = DEFAULT_ITEMS end describe Foo do before(:each) { Foo.class_variable_set :@items, Foo::DEFAULT_ITEMS } it "should have a default" do Foo.items.should eq(Foo::DEFAULT_ITEMS) end it "should allow items to be added" do Foo.items << "kittens" Foo.items.include?("kittens").should eq(true) end end 

Or maybe it's better to reload the class

 describe 'items' do before(:each) do Object.send(:remove_const, 'Foo') load 'foo.rb' end end 
+11
source

If your class has internal states that you would like to check, I find that using class_variable_get good way to approach this. This does not require you to expose any variable in the class, so the class can remain untouched.

 it 'increases number by one' do expect(YourClass.class_variable_get(:@@number)).to equal(0) YourClass.increase_by_one() expect(YourClass.class_variable_get(:@@number)).to equal(1) end 

I know that this is not what you ask for in your question, but in the title that brought me here.

+8
source

I found that this question has a slightly different problem - clearing a cached class variable between rspec examples.

In the module, I have an expensive class config, which I cache as follows:

 module Thingamizer def config @config ||= compute_config_the_hard_way() end end class Thing extend Thingamizer end 

In my Thing tests for compute_config_the_hard_way only for the first time. Subsequent calls used the cached version, even if I make fun of compute_config_the_hard_way to return different things in other tests.

I solved this problem by clearing @config before each example:

  before { Thing.instance_variable_set(:@config, nil) } 

Now I was obsessed with @config being a class variable, not an instance variable. I tried many options for class_variable_set without luck.

The fold here is that the Thing (class) is actually an instance of the class. Thus, what seems to be a class variable in a class method is actually an instance variable in an instance of the class (i.e. Thing). Once I class_variable_set this idea, using instance_variable_set instead of class_variable_set made sense.

See Using instance variables in class methods - Ruby for a discussion of class variables as instance variables.

0
source

All Articles