2

This is one of those cases where my code is working but my test is failing and I need to know what I am doing wrong?

I have a Project class with an all method that just spits out instances of this class:

class Project

    @@all_projects = []

    def initialize(options)
      @@all_projects << self
    end

    def self.all
    @@all_projects
  end
end

Now Project.all works just fine but the spec I am writing doesn't.

context "manipulating projects" do
    before do
        options1 = {
            name: 'Building house'
        }

        options2 = {
            name: 'Getting a loan from the Bank'
        }

        @project1 = Project.new(options1)
        @project2 = Project.new(options2)
    end
        it "can print all projects" do
      Project.all.should eq([@project1, @project2])
    end

The failure message I get is:

Project manipulating projects can print all projects
     Failure/Error: Project.all.should eq([@project1, @project2])

       expected: [Building house, Getting a loan from the Bank]
            got: [Building house, Building house, Building house, Getting a loan from the Bank, Building house, Getting a loan from the Bank]

Here is the full spec in a gist: https://gist.github.com/4535863

What am I doing wrong? How can I fix it?

4

2 に答える 2

3

It is doubling the results because it runs the before block for each test, where the class attribute is modified (when two new projects are initialized), and (according to the gist) the test you're referring to is the second one.

To avoid the problem you'll need to reset @@all_projects in an after block:

after do
  Project.class_variable_set :@@all_projects, []
end

See also: How can I clear class variables between rspec tests in ruby

(Thanks to @iain for the suggestion to move the reset code to an after block rather than a before block.)

于 2013-01-15T03:51:09.610 に答える
1

This doesn't use before blocks to set stinky instance variables.

describe Project do
  let(:options1){ 
    {
      name: 'Building house',
      priority: 2,
      tasks: []
    }
  }
  let(:options2) {
    {
      name: 'Getting a loan from the Bank',
      priority: 3,
      tasks: []
    }
  }
  let(:project1) { Project.new(options1) }
  let(:project2) { Project.new(options2) }

  context "while starting up" do

    subject { Project.new options1 }
    its(:name) { should include('Building house') }

    its(:tasks) { should be_empty }
  end

  context "manipulating projects" do
    before :all do
      Project.all.clear
    end

    subject { Project.all }
    its(:count) { should be > 0 }

    it { should eq [project1, project2] }

  end

end
于 2013-01-15T04:25:16.070 に答える