Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails / RSpec: How to test #initialize method?

Tags:

ruby

rspec2

How can I specify #initialize behaviour with RSpec? For example here:

generator.rb

class Generator
  attr_accessor :seed

  def initialize(seed = nil)
    @seed = seed || pick_seed
  end

  def pick_seed
    Time.now.to_i
  end
end

generator_spec.rb

require 'generator'

describe Generator

  it "calls 'pick_seed' method unless seed specified" do
  end

end

I'd like to set expectation that pick_seed method called from #initialize method.

like image 231
avsej Avatar asked Dec 25 '10 13:12

avsej


People also ask

How do I run an RSpec test?

Running tests by their file or directory names is the most familiar way to run tests with RSpec. RSpec can take a file name or directory name and run the file or the contents of the directory. So you can do: rspec spec/jobs to run the tests found in the jobs directory.

What is an RSpec test?

RSpec is a testing tool for Ruby, created for behavior-driven development (BDD). It is the most frequently used testing library for Ruby in production applications. Even though it has a very rich and powerful DSL (domain-specific language), at its core it is a simple tool which you can start using rather quickly.

Is RSpec unit test?

RSpec is a unit test framework for the Ruby programming language. RSpec is different than traditional xUnit frameworks like JUnit because RSpec is a Behavior driven development tool. What this means is that, tests written in RSpec focus on the "behavior" of an application being tested.


1 Answers

For me, expectations are about designing conversations among collaborators. So, you have to decide - is #pick_seed an internal implementation detail or part of a collaborating role's interface?

If pick_seed is an implementation detail, an expectation is the wrong tool for the job. And, since you have an accessor for seed, you can proceed thusly (notice the one-assertion-per-example):

class Generator
  attr_accessor :seed

  def initialize(seed = nil)
    @seed = seed || pick_seed
  end

  def pick_seed
    Time.now.to_i
  end
end

describe Generator do
  context "creating" do 
    context "when a seed is specified" do
      it "uses that seed" do
        seed = 123
        generator = Generator.new(seed)
        generator.seed.should == seed
      end
    end
    context "when a seed is not specified" do
      it "creates its own seed" do
        generator = Generator.new
        generator.seed.should_not be_nil
      end
    end
  end
end

OTOH, if picking the seed is part of the "seed picker" role, then mocks are valuable in designing the seed picker, and dependency injection is a standard method of assigning the roles. You could write something like:

class GeneratorWithCollaborator
  attr_accessor :seed

  def initialize(seed = nil, seed_picker = self)
    @seed = seed || seed_picker.pick_seed
  end

  def pick_seed
    Time.now.to_i
  end
end

describe GeneratorWithCollaborator do
  context "creating" do
    context "when a seed is specified" do
      it "uses that seed" do
        seed = 123
        seed_picker = double('seed picker')
        seed_picker.should_not_receive(:pick_seed)
        generator = GeneratorWithCollaborator.new(seed, seed_picker)
        generator.pick_seed
      end
    end

    context "when a seed is not specified" do
      it "delegates to its seed picker" do
        seed_picker = double('seed picker')
        seed_picker.should_receive(:pick_seed)
        generator = GeneratorWithCollaborator.new(nil, seed_picker)
      end
    end
  end
end
like image 163
Sean DeNigris Avatar answered Sep 23 '22 20:09

Sean DeNigris