24

I have the following class: I want to ensure the class url is only set once for all instances.

class DataFactory
  @@url = nil

  def initialize()
begin
    if @@url.nil?
       Rails.logger.debug "Setting url"
       @@url = MY_CONFIG["my value"]
    end
rescue Exception
  raise DataFactoryError, "Error!"
end
  end
end

I have two tests:

it "should log a message" do
  APP_CONFIG = {"my value" => "test"}
  Rails.stub(:logger).and_return(logger_mock)
  logger_mock.should_receive(:debug).with "Setting url"

  t = DataFactory.new
  t = nil
end

it "should throw an exception" do
  APP_CONFIG = nil

  expect {
    DataFactory.new
  }.to raise_error(DataFactoryError, /Error!/)
end

The problem is the second test never throws an exception as the @@url class variable is still set from the first test when the second test runs. Even though I have se the instance to nil at the end of the first test garbage collection has not cleared the memory before the second test runs:

Any ideas would be great! I did hear you could possibly use Class.new but I am not sure how to go about this.

1
  • Not exactly related to your problem, but: never use @@class variables in Ruby. Use @class instance variables instead. They behave far more predictably. Commented Nov 28, 2011 at 19:45

2 Answers 2

27
describe DataFactory
  before(:each) { DataFactory.class_variable_set :@@url, nil }
  ...
end
Sign up to request clarification or add additional context in comments.

1 Comment

When I ran this I got the following error: NameError: uninitialized class variable @@url in Object I got it to work using: before(:each) do DataFactory.class_eval {class_variable_set :@@url, nil} end I am using JRuby 1.6.5 which I believe uses Ruby 1.8.9 and class_variable_set might be private in this version so I had to use class_eval See: [khelll.com/blog/ruby/ruby-reflection-2/]
8

Here is an alternative to the accepted answer, which while wouldn't solve your particular example, I'm hoping it might help a few people with a question in the same vein. If the class in question doesn't specify a default value, and remains undefined until set, this seems to work:

describe DataFactory
  before(:each) do
    DataFactory.remove_class_variable :@@url if DataFactory.class_variable_defined? :@@url
  end
  ...
end

Works for me with a class with something more like:

def initialize
  @@url ||= MY_CONFIG["my value"]
  ...
end

1 Comment

and similarly with class instance variable: described_class.remove_instance_variable(:@foo) if described_class.instance_variable_defined?(:@foo)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.