0

How do I test that an instance method is properly modifying an instance variable?

Given the class:

class MyClass
  attr_reader :ary
  def initialize
    @ary = []
  end
  def update (value)
    @ary << value
  end
end

How would I test that #update is correctly modifying @ary?
So far I have:

describe MyClass do
  before { @my_class = MyClass.new }
  describe '#update' do
    it 'should correctly update the value' do
       expect(@my_class.update('some_value')).to #what comes next?

The matcher is looking to evaluate the return value of #update, not the value of @ary, which is what I want.

1
  • Should I insert a before {@my_class.update('some_value'} after describe '#update' do, then use expect(@my_class.ary).to eq(['some_value']) ? Commented Dec 31, 2015 at 10:58

2 Answers 2

1

Here's a concise example

describe MyClass do
  describe "#update" do
    it "appends the argument to the array" do
       subject.update(value = 'some_value')
       expect(subject.ary).to eq([value])
    end
  end
end

A few notes compared to your initial code. First of all, you can rely on subject. subject is defined as

described_class.new

It's like having

describe MyClass do
  subject { described_class.new }

  describe "#update" do
    ...
  end
end

or

describe MyClass do
  describe "#update" do
    subject = described_class.new
  end
end

which essentially means

describe MyClass do
  describe "#update" do
    subject = MyClass.new
  end
end

If you just want to test an instance, use subject. Do not use before actions to set instance variables.

The following line

subject.update(value = 'some_value')
expect(subject.ary).to eq([value])

is essentially a shortcut for

value = 'some_value'
subject.update(value)
expect(subject.ary).to eq([value])

It helps me to not write the expected string twice. The rest should be quite easy to understand.

You may also want to test the return value, if this is relevant.

describe MyClass do
  describe "#update" do
    it "appends the argument to the array" do
      subject.update(value = 'some_value')
      expect(subject.ary).to eq([value])
    end

    it "returns the item that was added" do
      value = 'some_value'
      expect(subject.update(value)).to eq(value)
    end
  end
end
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the tips. Is there some kind of consensus on when to use subject? I have seen numerous references to this article that says to avoid subject for simpler tests.
For very simple tests, I generally rely on subject, whereas for more complex specs I tend to use explicit subjects to make sure the code is more readable. Actually, I personally prefer to always have an explicit subject either in the spec block or as subject {} statement. But this is a personal preference.
Agree with always using explicit class name instead of described_class.
0

Call the method first, then check for @ary

describe MyClass do
  before { @my_class = MyClass.new }
    describe '#update' do
      it 'should correctly update the value' do
        @my_class.update('some_value')
        expect(@my_class.ary).to equal(['some_value'])

Comments

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.